FIX * ENHANCEMENTS

* ADD 用户活动统计图表功能
  * ADD 用户精选项目功能
  * ADD 用户贡献度统计图表功能
  * ADD 用户开发能力数据统计工
  * ADD 用户角色定位展示功能
  * ADD 用户专业定位标签展示功能
  * ADD 修改用户基本资料功能
  * ADD 更改密码功能
  * ADD 用户个人主页基本现在展示可配置功能

* BUGFIXES
  * Fix 解决一些bug
  * Fix 优化美化页面change license
This commit is contained in:
jasder
2021-06-09 17:52:57 +08:00
103 changed files with 3240 additions and 524 deletions

View File

@@ -203,6 +203,25 @@ class AccountsController < ApplicationController
# session[:user_id] = @user.id
end
def change_password
@user = User.find_by(login: params[:login])
return render_error("未找到相关用户!") if @user.blank?
return render_error("旧密码不正确") unless @user.check_password?(params[:old_password])
sync_params = {
password: params[:password].to_s,
email: @user.mail
}
interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params)
if interactor.success?
@user.update_attribute(:password, params[:password])
render_ok
else
render_error(interactor.error)
end
end
# 忘记密码
def reset_password
begin

View File

@@ -32,7 +32,7 @@ class Admins::AuthSchoolsController < Admins::BaseController
def search_manager
school = School.find_by(id: params[:school_id])
user_ids = school&.ec_school_users&.pluck(:user_id)
@users = User.where.not(id: user_ids).where("concat(lastname, firstname) like ?", "%#{params[:name].strip.to_s}%").limit(10)
@users = User.where.not(id: user_ids).where("CONCAT_WS(lastname, firstname, nickname) like ?", "%#{params[:name].strip.to_s}%").limit(10)
end
# 添加认证学校管理员

View File

@@ -32,7 +32,7 @@ class Admins::LaboratoriesController < Admins::BaseController
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword '\
like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword '\
'OR mirror_repositories.name LIKE :keyword'
shixuns = shixuns.joins(:user, :mirror_repositories).where(like_sql, keyword: "%#{keyword}%")
end
@@ -48,7 +48,7 @@ class Admins::LaboratoriesController < Admins::BaseController
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword'
like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword'
subjects = subjects.joins(:user).where(like_sql, keyword: "%#{keyword}%")
end

View File

@@ -773,7 +773,26 @@ class ApplicationController < ActionController::Base
def base_url
request.base_url
end
def convert_image!
@image = params[:image] || user_params[:image]
return unless @image.present?
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
if @image.class == ActionDispatch::Http::UploadedFile
render_error('请上传文件') if @image.size.zero?
render_error('文件大小超过限制') if @image.size > max_size.to_i
else
image = @image.to_s.strip
return render_error('请上传正确的图片') if image.blank?
@image = Util.convert_base64_image(image, max_size: max_size.to_i)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
def avatar_path(object)
ApplicationController.helpers.disk_filename(object.class, object.id)
end
private
def object_not_found

View File

@@ -18,7 +18,7 @@ class MembersController < ApplicationController
scope = @project.members.includes(:roles, user: :user_extension)
search = params[:search].to_s.downcase
role = params[:role].to_s
scope = scope.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
scope = scope.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
scope = scope.joins(:roles).where("roles.name LIKE ?", "%#{role}%") if role.present?
@total_count = scope.size

View File

@@ -5,7 +5,7 @@ class Organizations::OrganizationUsersController < Organizations::BaseController
def index
@organization_users = @organization.organization_users.includes(:user)
search = params[:search].to_s.downcase
@organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
@organization_users = @organization_users.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.mail, users.nickname)) LIKE ?", "%#{search.split(" ").join('|')}%") if search.present?
@organization_users = kaminari_paginate(@organization_users)
end

View File

@@ -70,25 +70,6 @@ class Organizations::OrganizationsController < Organizations::BaseController
end
private
def convert_image!
return unless params[:image].present?
max_size = EduSetting.get('upload_avatar_max_size') || 2 * 1024 * 1024 # 2M
if params[:image].class == ActionDispatch::Http::UploadedFile
@image = params[:image]
render_error('请上传文件') if @image.size.zero?
render_error('文件大小超过限制') if @image.size > max_size.to_i
else
image = params[:image].to_s.strip
return render_error('请上传正确的图片') if image.blank?
@image = Util.convert_base64_image(image, max_size: max_size.to_i)
end
rescue Base64ImageConverter::Error => ex
render_error(ex.message)
end
def avatar_path(organization)
ApplicationController.helpers.disk_filename(organization.class, organization.id)
end
def organization_params
params.permit(:name, :description, :website, :location,

View File

@@ -177,7 +177,7 @@ class ProjectsController < ApplicationController
end
def recommend
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(id: :desc)
@projects = Project.recommend.includes(:repository, :project_category, :owner).order(visits: :desc)
end
def about

View File

@@ -0,0 +1,26 @@
class Users::HeadmapsController < Users::BaseController
def index
result = Gitea::User::HeadmapService.call(observed_user.login, start_stamp, end_stamp)
@headmaps = result[2]
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def start_stamp
if params[:year].present?
Date.new(params[:year], 1).to_time.to_i
else
Date.today.to_time.to_i - 365*24*60*60
end
end
def end_stamp
if params[:year].present?
Date.new(params[:year], 1).to_time.to_i + 365*24*60*60
else
Date.today.to_time.to_i
end
end
end

View File

@@ -0,0 +1,45 @@
class Users::IsPinnedProjectsController < Users::BaseController
before_action :private_user_resources!, only: [:pin]
def index
@is_pinned_projects = observed_user.pinned_projects.order(position: :desc, created_at: :asc).includes(project: [:project_category, :project_language, :repository]).order(position: :desc)
@is_pinned_projects = kaminari_paginate(@is_pinned_projects)
end
def pin
observed_user.is_pinned_project_ids = is_pinned_project_ids
render_ok
rescue ActiveRecord::RecordNotFound => e
render_not_found
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
def update
@pinned_project = PinnedProject.find_by_id(params[:id])
@pinned_project.attributes = pinned_project_params
if @pinned_project.save
render_ok
else
render_error
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end
private
def is_pinned_project_ids
if params[:is_pinned_project_ids].present?
return params[:is_pinned_project_ids].select{|id| observed_user.full_member_projects.visible.pluck(:id).include?(id.to_i) }
end
if params[:is_pinned_project_id].present?
return observed_user.is_pinned_project_ids unless observed_user.full_member_projects.visible.pluck(:id).include?(params[:is_pinned_project_id].to_i)
return observed_user.is_pinned_project_ids.include?(params[:is_pinned_project_id].to_i) ? observed_user.is_pinned_project_ids : observed_user.is_pinned_project_ids.push(params[:is_pinned_project_id].to_i)
end
end
def pinned_project_params
params.require(:pinned_project).permit(:position)
end
end

View File

@@ -0,0 +1,11 @@
class Users::ProjectTrendsController < Users::BaseController
def index
if params[:date].present?
@project_trends = observed_user.project_trends.where("DATE(created_at) = ?", params[:date])
else
@project_trends = observed_user.project_trends
end
@project_trends = kaminari_paginate(@project_trends.includes(:trend, :project).order(created_at: :desc))
end
end

View File

@@ -0,0 +1,217 @@
class Users::StatisticsController < Users::BaseController
before_action :preload_develop_data, only: [:develop]
# 近期活动统计
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.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
# 开发能力
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
# 用户被follow数量
@follow_count = Cache::UserFollowCountService.call(observed_user)
@platform_follow_count = Cache::PlatformFollowCountService.call
# 用户pr数量
@pullrequest_count = Cache::UserPullrequestCountService.call(observed_user)
@platform_pullrequest_count = Cache::PlatformPullrequestCountService.call
# 用户issue数量
@issues_count = Cache::UserIssueCountService.call(observed_user)
@platform_issues_count = Cache::PlatformIssueCountService.call
# 用户总项目数
@project_count = Cache::UserProjectCountService.call(observed_user)
@platform_project_count = Cache::PlatformProjectCountService.call
# 用户项目被fork数量
@fork_count = Cache::UserProjectForkCountService.call(observed_user)
@platform_fork_count = Cache::PlatformProjectForkCountService.call
# 用户项目关注数
@project_watchers_count = Cache::UserProjectWatchersCountService.call(observed_user)
@platform_project_watchers_count = Cache::PlatformProjectWatchersCountService.call
# 用户项目点赞数
@project_praises_count = Cache::UserProjectPraisesCountService.call(observed_user)
@platform_project_praises_count = Cache::PlatformProjectPraisesCountService.call
# 用户不同语言项目数量
@project_languages_count = Cache::UserProjectLanguagesCountService.call(observed_user)
@platform_project_languages_count = Cache::PlatformProjectLanguagesCountService.call
end
end
end

View File

@@ -6,6 +6,7 @@ class UsersController < ApplicationController
before_action :check_user_exist, only: [:show, :homepage_info,:projects, :watch_users, :fan_users, :hovercard]
before_action :require_login, only: %i[me list sync_user_info]
before_action :connect_to_ci_db, only: [:get_user_info]
before_action :convert_image!, only: [:update]
skip_before_action :check_sign, only: [:attachment_show]
def connect_to_ci_db(options={})
@@ -62,7 +63,7 @@ class UsersController < ApplicationController
def fan_users
watchers = @user.watchers.includes(:user).order("watchers.created_at desc")
watchers = watchers.joins(:user).where("LOWER(concat(users.lastname, users.firstname, users.login)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present?
watchers = watchers.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.login, users.nickname)) LIKE ?", "%#{params[:search].split(" ").join('|')}%") if params[:search].present?
@watchers_count = watchers.size
@watchers = paginate(watchers)
@@ -72,9 +73,13 @@ class UsersController < ApplicationController
end
def update
@user = User.find params[:id]
@user.update!(user_params)
render_ok
return render_not_found unless @user = User.find_by_id(params[:id]) || User.find_by(login: params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
Util.write_file(@image, avatar_path(@user)) if user_params[:image].present?
@user.attributes = user_params.except(:image)
unless @user.save
render_error(@user.errors.full_messages.join(", "))
end
end
def me
@@ -274,11 +279,13 @@ class UsersController < ApplicationController
end
def user_params
params.require(:user).permit(:nickname, :lastname, :show_realname,:login,:mail,
params.require(:user).permit(:nickname, :image,
user_extension_attributes: [
:gender, :location, :location_city,
:occupation, :technical_title,
:school_id, :department_id,:identity, :student_id, :description]
:school_id, :department_id, :province, :city,
:custom_department, :identity, :student_id, :description,
:show_email, :show_location, :show_department]
)
end

View File

@@ -11,7 +11,7 @@ class UsersForPrivateMessagesController < ApplicationController
return
end
users = users.where('LOWER(concat(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%")
users = users.where('LOWER(CONCAT_WS(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%")
@users = users.limit(10).includes(:user_extension)
end

View File

@@ -86,7 +86,7 @@ class Weapps::CoursesController < Weapps::BaseController
end
if search.present?
@teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT(users.lastname, users.firstname)) like ?", "%#{search}%")
@teacher_list = @teacher_list.joins(:user).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ?", "%#{search}%")
end
@teacher_list_size = @teacher_list.size
@@ -127,7 +127,7 @@ class Weapps::CoursesController < Weapps::BaseController
@students = CourseMember.students(@course)
if search.present?
@students = @students.joins(user: :user_extension).where("LOWER(CONCAT(users.lastname, users.firstname)) like ? or
@students = @students.joins(user: :user_extension).where("LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) like ? or
user_extensions.student_id like ?", "%#{search}%", "%#{search}%")
end

View File

@@ -86,7 +86,7 @@ class ZipsController < ApplicationController
#搜索
if params[:search].present?
@ex_users = @ex_users.joins(user: :user_extension).where("CONCAT(lastname, firstname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%")
@ex_users = @ex_users.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ? OR student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%")
end
default_ex_users_size = @ex_users&.size
@@ -130,7 +130,7 @@ class ZipsController < ApplicationController
end
unless params[:search].blank?
@all_student_works = @all_student_works.joins(user: :user_extension).where("concat(lastname, firstname) like ?
@all_student_works = @all_student_works.joins(user: :user_extension).where("CONCAT_WS(lastname, firstname, nickname) like ?
or student_id like ?", "%#{params[:search]}%", "%#{params[:search]}%")
end

View File

@@ -94,7 +94,7 @@ module TagChosenHelper
def render_issue_tags(project)
# project.issue_tags.last&.cache_key
cache_key = "all_issue_tags/#{project.issue_tags.maximum('updated_at')}"
cache_key = "project-#{project.id}/all_issue_tags/size-#{project.issue_tags.size}/#{project.issue_tags.maximum('updated_at')}"
Rails.cache.fetch(cache_key) do
project.issue_tags.select(:id, :name, :color).collect do |event|
@@ -109,7 +109,7 @@ module TagChosenHelper
end
def render_cache_milestones(project)
cache_key = "all_milestones/#{project.versions.maximum('updated_on')}"
cache_key = "project-#{project.id}/all_milestones/size-#{project.versions.size}/#{project.versions.maximum('updated_on')}"
Rails.cache.fetch(cache_key) do
project.versions.select(:id, :name, :status).collect do |event|
@@ -124,7 +124,7 @@ module TagChosenHelper
end
def render_cache_collaborators(project)
cache_key = "all_collaborators/#{project.all_collaborators.maximum('created_on')}"
cache_key = "project-#{project.id}/all_collaborators/size-#{project.all_collaborators.size}/#{project.all_collaborators.maximum('updated_on')}"
Rails.cache.fetch(cache_key) do
project.all_collaborators.order(created_on: :desc).collect do |user|
{

View File

@@ -0,0 +1,14 @@
class ResetPlatformCacheJob < ApplicationJob
queue_as :cache
def perform
Cache::PlatformFollowCountService.new.reset
Cache::PlatformIssueCountService.new.reset
Cache::PlatformProjectCountService.new.reset
Cache::PlatformProjectForkCountService.new.reset
Cache::PlatformProjectLanguagesCountService.new.reset
Cache::PlatformProjectPraisesCountService.new.reset
Cache::PlatformProjectWatchersCountService.new.reset
Cache::PlatformPullrequestCountService.new.reset
end
end

View File

@@ -0,0 +1,14 @@
class ResetUserCacheJob < ApplicationJob
queue_as :cache
def perform(user)
Cache::UserFollowCountService.new(user).reset
Cache::UserIssueCountService.new(user).reset
Cache::UserProjectCountService.new(user).reset
Cache::UserProjectForkCountService.new(user).reset
Cache::UserProjectLanguagesCountService.new(user).reset
Cache::UserProjectPraisesCountService.new(user).reset
Cache::UserProjectWatchersCountService.new(user).reset
Cache::UserPullrequestCountService.new(user).reset
end
end

View File

@@ -5,7 +5,27 @@ class SyncMirroredRepositoryJob < ApplicationJob
repo = Repository.find_by(id: repo_id)
current_user = User.find_by(id: user_id)
return if repo.blank? || current_user.blank?
result = Gitea::Repository::SyncMirroredService.new(repo.owner.login, repo.identifier, token: current_user.gitea_token).call
# TODO
# 先同步镜像库
if repo.config_accelerator?
puts "[gitea-accelerator]: ###### 镜像库开始同步 ######"
result = Gitea::Accelerator::SyncMirroredService.call(repo.identifier)
puts "[gitea-accelerator]: ###### 镜像库同步状态为 #{result[:status]}"
# TODO 暂时解决从镜像库镜像动作时间先执行的问题
# 避免了Gitea::Repository::SyncMirroredService先执行后加速器Gitea::Accelerator::SyncMirroredService
# 再执行的导致Gitea::Repository::SyncMirroredService执行镜像不是最新代码的问题
sleep 3.seconds
end
sync_common!(repo, current_user)
end
def sync_common!(repo, user)
result = Gitea::Repository::SyncMirroredService.call(repo.owner.login,
repo.identifier, token: user.gitea_token)
repo&.mirror.set_status! if result[:status] === 200
end
end

View File

@@ -16,4 +16,12 @@ class ApplicationRecord < ActiveRecord::Base
def allow_sync_to_trustie?
Rails.env.production? && EduSetting.get('host_name') == 'https://www.educoder.net'
end
def reset_user_cache_async_job(user)
ResetUserCacheJob.perform_later(user)
end
def reset_platform_cache_async_job
ResetPlatformCacheJob.perform_later
end
end

View File

@@ -1,42 +1,42 @@
# == 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 :string(255)
# 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")
# link :string(255)
# clone_id :integer
#
# Indexes
#
# 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_created_on (created_on)
#
# == 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")
#
# 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)
#
class Attachment < ApplicationRecord
include BaseModel
include Publicable
@@ -51,7 +51,7 @@ class Attachment < ApplicationRecord
# 二级目录
# belongs_to :course_second_category, optional: true
scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(concat(users.lastname, users.firstname)) LIKE :search",
scope :by_filename_or_user_name, -> (keywords) { joins(:author).where("filename like :search or LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE :search",
:search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank? }
scope :by_keywords, -> (keywords) { where("filename LIKE ?", "%#{keywords.split(" ").join('|')}%") unless keywords.blank? }
scope :ordered, -> (opts = {}) { order("#{opts[:sort_type]} #{opts[:sort] == 1 ? 'asc': 'desc'}") }

View File

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

View File

@@ -9,6 +9,7 @@ module ProjectOperable
has_many :reporters, -> { joins(:roles).where(roles: { name: 'Reporter' }) }, class_name: 'Member'
has_many :writable_members, -> { joins(:roles).where.not(roles: {name: 'Reporter'}) }, class_name: 'Member'
has_many :team_projects, dependent: :destroy
has_many :teams, through: :team_projects, source: :team
end
def set_owner_permission(creator)

View File

@@ -20,4 +20,12 @@ class ForkUser < ApplicationRecord
belongs_to :user
belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id
after_save :reset_cache_data
after_destroy :reset_cache_data
def reset_cache_data
self.reset_platform_cache_async_job
self.reset_user_cache_async_job(self.project.owner)
end
end

View File

@@ -6,7 +6,7 @@
# tracker_id :integer not null
# project_id :integer not null
# subject :string(255) default(""), not null
# description :text(4294967295)
# description :text(65535)
# due_date :date
# category_id :integer
# status_id :integer not null
@@ -14,6 +14,7 @@
# priority_id :integer not null
# fixed_version_id :integer
# author_id :integer not null
# lock_version :integer default("0"), not null
# created_on :datetime
# updated_on :datetime
# start_date :date
@@ -27,7 +28,7 @@
# closed_on :datetime
# project_issues_index :integer
# issue_type :string(255)
# token :integer default("0")
# token :string(255)
# issue_tags_value :string(255)
# is_lock :boolean default("0")
# issue_classify :string(255)
@@ -50,7 +51,7 @@
class Issue < ApplicationRecord
#issue_type 1为普通2为悬赏
belongs_to :project, :counter_cache => true
belongs_to :project, counter_cache: true, touch: true
belongs_to :tracker,optional: true
has_many :project_trends, as: :trend, dependent: :destroy
has_one :pull_request
@@ -75,8 +76,13 @@ class Issue < ApplicationRecord
scope :issue_index_includes, ->{includes(:tracker, :priority, :version, :issue_status, :journals,:issue_tags,user: :user_extension)}
after_update :change_versions_count
after_destroy :update_closed_issues_count_in_project!
after_save :reset_cache_data
after_destroy :update_closed_issues_count_in_project!, :reset_cache_data
def reset_cache_data
self.reset_platform_cache_async_job
self.reset_user_cache_async_job(self.user)
end
def get_assign_user
User&.find_by_id(self.assigned_to_id) if self.assigned_to_id.present?

View File

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

View File

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

View File

@@ -0,0 +1,22 @@
# == Schema Information
#
# Table name: pinned_projects
#
# id :integer not null, primary key
# user_id :integer
# project_id :integer
# position :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_pinned_projects_on_project_id (project_id)
# index_pinned_projects_on_user_id (user_id)
#
class PinnedProject < ApplicationRecord
belongs_to :user
belongs_to :project
end

View File

@@ -1,26 +1,35 @@
# == Schema Information
#
# Table name: praise_treads
#
# id :integer not null, primary key
# user_id :integer not null
# praise_tread_object_id :integer
# praise_tread_object_type :string(255)
# praise_or_tread :integer default("1")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# praise_tread (praise_tread_object_id,praise_tread_object_type)
#
# == Schema Information
#
# Table name: praise_treads
#
# id :integer not null, primary key
# user_id :integer not null
# praise_tread_object_id :integer
# praise_tread_object_type :string(255)
# praise_or_tread :integer default("1")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# praise_tread (praise_tread_object_id,praise_tread_object_type)
#
class PraiseTread < ApplicationRecord
belongs_to :user
belongs_to :praise_tread_object, polymorphic: true, counter_cache: :praises_count
has_many :tidings, :as => :container, :dependent => :destroy
after_create :send_tiding
after_save :reset_cache_data
after_destroy :reset_cache_data
def reset_cache_data
self.reset_platform_cache_async_job
if self.praise_tread_object.is_a?(Project)
self.reset_user_cache_async_job(self.praise_tread_object&.owner)
end
end
def send_tiding
case self.praise_tread_object_type

View File

@@ -1,76 +1,65 @@
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255) default(""), not null
# description :text(4294967295)
# homepage :string(255) default("")
# is_public :boolean default("1"), not null
# parent_id :integer
# created_on :datetime
# updated_on :datetime
# identifier :string(255)
# status :integer default("1"), not null
# lft :integer
# rgt :integer
# inherit_members :boolean default("0"), not null
# project_type :integer default("0")
# hidden_repo :boolean default("0"), not null
# attachmenttype :integer default("1")
# user_id :integer
# dts_test :integer default("0")
# enterprise_name :string(255)
# organization_id :integer
# project_new_type :integer
# gpid :integer
# forked_from_project_id :integer
# forked_count :integer default("0")
# publish_resource :integer default("0")
# visits :integer default("0")
# hot :integer default("0")
# invite_code :string(255)
# qrcode :string(255)
# qrcode_expiretime :integer default("0")
# script :text(65535)
# training_status :integer default("0")
# rep_identifier :string(255)
# project_category_id :integer
# project_language_id :integer
# praises_count :integer default("0")
# watchers_count :integer default("0")
# issues_count :integer default("0")
# pull_requests_count :integer default("0")
# language :string(255)
# versions_count :integer default("0")
# issue_tags_count :integer default("0")
# closed_issues_count :integer default("0")
# open_devops :boolean default("0")
# gitea_webhook_id :integer
# open_devops_count :integer default("0")
# recommend :boolean default("0")
# platform :integer default("0")
# license_id :integer
# ignore_id :integer
# default_branch :string(255) default("master")
# website :string(255)
# lesson_url :string(255)
#
# Indexes
#
# index_projects_on_forked_from_project_id (forked_from_project_id)
# index_projects_on_identifier (identifier)
# index_projects_on_is_public (is_public)
# index_projects_on_lft (lft)
# index_projects_on_name (name)
# index_projects_on_platform (platform)
# index_projects_on_project_type (project_type)
# index_projects_on_recommend (recommend)
# index_projects_on_rgt (rgt)
# index_projects_on_status (status)
# index_projects_on_updated_on (updated_on)
#
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# name :string(255) default(""), not null
# description :text(65535)
# homepage :string(255) default("")
# is_public :boolean default("1"), not null
# parent_id :integer
# created_on :datetime
# updated_on :datetime
# identifier :string(255)
# status :integer default("1"), not null
# lft :integer
# rgt :integer
# inherit_members :boolean default("0"), not null
# project_type :integer default("0")
# hidden_repo :boolean default("0"), not null
# attachmenttype :integer default("1")
# user_id :integer
# dts_test :integer default("0")
# enterprise_name :string(255)
# organization_id :integer
# project_new_type :integer
# gpid :integer
# forked_from_project_id :integer
# forked_count :integer default("0")
# publish_resource :integer default("0")
# visits :integer default("0")
# hot :integer default("0")
# invite_code :string(255)
# qrcode :string(255)
# qrcode_expiretime :integer default("0")
# script :text(65535)
# training_status :integer default("0")
# rep_identifier :string(255)
# project_category_id :integer
# project_language_id :integer
# license_id :integer
# ignore_id :integer
# praises_count :integer default("0")
# watchers_count :integer default("0")
# issues_count :integer default("0")
# pull_requests_count :integer default("0")
#
# Indexes
#
# index_projects_on_forked_from_project_id (forked_from_project_id)
# index_projects_on_identifier (identifier)
# index_projects_on_is_public (is_public)
# index_projects_on_lft (lft)
# index_projects_on_name (name)
# index_projects_on_platform (platform)
# index_projects_on_project_type (project_type)
# index_projects_on_recommend (recommend)
# index_projects_on_rgt (rgt)
# index_projects_on_status (status)
# index_projects_on_updated_on (updated_on)
#
class Project < ApplicationRecord
include Matchable
@@ -111,11 +100,13 @@ class Project < ApplicationRecord
has_many :praise_treads, as: :praise_tread_object, dependent: :destroy
has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
has_one :project_detail, dependent: :destroy
has_many :team_projects, dependent: :destroy
has_many :project_units, dependent: :destroy
has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy
has_many :pinned_projects, dependent: :destroy
has_many :has_pinned_users, through: :pinned_projects, source: :user
after_save :check_project_members
after_save :check_project_members, :reset_cache_data
after_destroy :reset_cache_data
scope :project_statics_select, -> {select(:id,:name, :is_public, :identifier, :status, :project_type, :user_id, :forked_count, :visits, :project_category_id, :project_language_id, :license_id, :ignore_id, :watchers_count, :created_on)}
scope :no_anomory_projects, -> {where("projects.user_id is not null and projects.user_id != ?", 2)}
scope :recommend, -> { visible.project_statics_select.where(recommend: true) }
@@ -123,6 +114,14 @@ class Project < ApplicationRecord
delegate :content, to: :project_detail, allow_nil: true
delegate :name, to: :license, prefix: true, allow_nil: true
def reset_cache_data
if changes[:user_id].present?
first_owner = Owner.find_by_id(changes[:user_id].first)
self.reset_user_cache_async_job(first_owner)
end
self.reset_platform_cache_async_job
self.reset_user_cache_async_job(self.owner)
end
def self.search_project(search)
ransack(name_or_identifier_cont: search)

View File

@@ -8,6 +8,11 @@
# projects_count :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
#
# Indexes
#
# index_project_categories_on_ancestry (ancestry)
#
class ProjectCategory < ApplicationRecord

View File

@@ -16,11 +16,6 @@
# head :string(255)
# base :string(255)
# issue_id :integer
# fork_project_id :integer
# is_original :boolean default("0")
# comments_count :integer default("0")
# commits_count :integer default("0")
# files_count :integer default("0")
#
class PullRequest < ApplicationRecord
@@ -31,13 +26,21 @@ class PullRequest < ApplicationRecord
belongs_to :issue
belongs_to :user
belongs_to :project, :counter_cache => true
belongs_to :project, counter_cache: true, touch: true
# belongs_to :fork_project, foreign_key: :fork_project_id
has_many :pull_request_assigns, foreign_key: :pull_request_id
has_many :pull_request_tags, foreign_key: :pull_request_id
has_many :project_trends, as: :trend, dependent: :destroy
has_many :attachments, as: :container, dependent: :destroy
after_save :reset_cache_data
after_destroy :reset_cache_data
def reset_cache_data
self.reset_platform_cache_async_job
self.reset_user_cache_async_job(self.user)
end
def fork_project
Project.find_by(id: self.fork_project_id)
end

View File

@@ -27,6 +27,7 @@
#
# Indexes
#
# index_repositories_on_identifier (identifier)
# index_repositories_on_project_id (project_id)
# index_repositories_on_user_id (user_id)
#
@@ -82,5 +83,8 @@ class Repository < ApplicationRecord
source_clone_url.blank? ? mirror_url : source_clone_url
end
def config_accelerator?
!source_clone_url.blank?
end
end

View File

@@ -39,15 +39,13 @@
# business :boolean default("0")
# profile_completed :boolean default("0")
# laboratory_id :integer
# is_shixun_marker :boolean default("0")
# admin_visitable :boolean default("0")
# collaborator :boolean default("0")
# platform :string(255) default("0")
# gitea_token :string(255)
# gitea_uid :integer
# is_shixun_marker :boolean default("0")
# is_sync_pwd :boolean default("1")
# watchers_count :integer default("0")
# devops_step :integer default("0")
# gitea_token :string(255)
# platform :string(255)
#
# Indexes
#
@@ -55,9 +53,8 @@
# index_users_on_homepage_engineer (homepage_engineer)
# index_users_on_homepage_teacher (homepage_teacher)
# index_users_on_laboratory_id (laboratory_id)
# index_users_on_login (login) UNIQUE
# index_users_on_mail (mail) UNIQUE
# index_users_on_phone (phone) UNIQUE
# index_users_on_login (login)
# index_users_on_mail (mail)
# index_users_on_type (type)
#
@@ -164,11 +161,16 @@ class User < Owner
has_many :organization_users, dependent: :destroy
has_many :organizations, through: :organization_users
has_many :pinned_projects, dependent: :destroy
has_many :is_pinned_projects, through: :pinned_projects, source: :project
accepts_nested_attributes_for :is_pinned_projects
has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :pull_requests, dependent: :destroy
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
scope :like, lambda { |keywords|
sql = "CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR nickname LIKE :keyword"
sql = "CONCAT_WS(lastname, firstname, nickname) LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search"
where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
}
@@ -176,7 +178,9 @@ class User < Owner
attr_accessor :password, :password_confirmation
delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true
delegate :description, :gender, :department_id, :school_id, :location, :location_city,
:show_email, :show_location, :show_department,
:technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true
before_save :update_hashed_password
after_create do
@@ -195,6 +199,13 @@ class User < Owner
validate :validate_sensitive_string
validate :validate_password_length
# 用户参与的所有项目
def full_member_projects
normal_projects = Project.members_projects(self.id).to_sql
org_projects = Project.joins(teams: :team_users).where(team_users: {user_id: self.id}).to_sql
return Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
end
def name
login
end

View File

@@ -12,9 +12,7 @@
#
# Indexes
#
# 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)
# index_user_actions_on_ip (ip)
#
class UserAction < ApplicationRecord

View File

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

View File

@@ -22,9 +22,12 @@
# school_id :integer
# description :string(255) default("")
# department_id :integer
# honor :text(65535)
# edu_background :integer
# edu_entry_year :integer
# province :string(255)
# city :string(255)
# custom_department :string(255)
# show_email :boolean default("0")
# show_location :boolean default("0")
# show_department :boolean default("0")
#
# Indexes
#
@@ -33,25 +36,25 @@
# index_user_extensions_on_user_id (user_id)
#
class UserExtension < ApplicationRecord
# identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者
enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 }
belongs_to :user, touch: true
belongs_to :school, optional: true
# belongs_to :department, optional: true
# before_save :set_laboratory_school
def identity_text
I18n.t("user.identity.#{identity}")
end
private
def set_laboratory_school
# return unless new_record?
# self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site?
end
end
class UserExtension < ApplicationRecord
# identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者
enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 }
belongs_to :user, touch: true
belongs_to :school, optional: true
# belongs_to :department, optional: true
# before_save :set_laboratory_school
def identity_text
I18n.t("user.identity.#{identity}")
end
private
def set_laboratory_school
# return unless new_record?
# self.school_id = Laboratory.current.school_id if school_id.blank? && !Laboratory.current.main_site?
end
end

View File

@@ -24,7 +24,7 @@
#
class Version < ApplicationRecord
belongs_to :project, counter_cache: true
belongs_to :project, counter_cache: true, touch: true
has_many :issues, class_name: "Issue", foreign_key: "fixed_version_id"
belongs_to :user, optional: true

View File

@@ -15,10 +15,24 @@
# watchers_user_id_type (user_id,watchable_type)
#
class Watcher < ApplicationRecord
belongs_to :user
belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count
scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)}
end
class Watcher < ApplicationRecord
belongs_to :user
belongs_to :watchable, polymorphic: true, counter_cache: :watchers_count
scope :watching_users, ->(watchable_id){ where("watchable_type = ? and user_id = ?",'User',watchable_id)}
after_save :reset_cache_data
after_destroy :reset_cache_data
def reset_cache_data
if self.watchable.is_a?(User)
self.reset_user_cache_async_job(self.watchable)
end
if self.watchable.is_a?(Project)
self.reset_user_cache_async_job(self.watchable&.owner)
end
self.reset_platform_cache_async_job
end
end

View File

@@ -26,7 +26,7 @@ class Admins::ApplyItemBankQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins(user: { user_extension: :school })
.where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
.where('CONCAT_WS(lastname,firstname, nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])

View File

@@ -26,7 +26,7 @@ class Admins::ApplyUserAuthenticationQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip
if keyword.present?
applies = applies.joins(user: { user_extension: :school })
.where('CONCAT(lastname,firstname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
.where('CONCAT_WS(lastname,firstname,nickname) LIKE :keyword OR schools.name LIKE :keyword', keyword: "%#{keyword}%")
end
custom_sort(applies, params[:sort_by], params[:sort_direction])

View File

@@ -19,7 +19,7 @@ class Admins::CourseListQuery < ApplicationQuery
case search_type
when "0"
course_lists = course_lists.joins(:user)
.where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%")
.where('CONCAT_WS(lastname, firstname, nickname) like :keyword', keyword: "%#{keyword}%")
when "1"
course_lists = course_lists.where('name like :keyword', keyword: "%#{keyword}%")
end

View File

@@ -35,7 +35,7 @@ class Admins::CourseQuery < ApplicationQuery
# 关键字
keyword = params[:keyword].to_s.strip
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword'
sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR courses.name LIKE :keyword OR course_lists.name LIKE :keyword'
courses = courses.joins(:teacher, :course_list).where(sql, keyword: "%#{keyword}%")
end

View File

@@ -11,7 +11,7 @@ class Admins::LaboratoryShixunQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'shixuns.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword'
like_sql = 'shixuns.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword'
laboratory_shixuns = laboratory_shixuns.joins(shixun: :user).where(like_sql, keyword: "%#{keyword}%")
end

View File

@@ -11,7 +11,7 @@ class Admins::LaboratorySubjectQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip
if keyword.present?
like_sql = 'subjects.name LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword'
like_sql = 'subjects.name LIKE :keyword OR CONCAT_WS(users.lastname, users.firstname, users.nickname) LIKE :keyword'
laboratory_subjects = laboratory_subjects.joins(subject: :user).where(like_sql, keyword: "%#{keyword}%")
end

View File

@@ -40,7 +40,7 @@ class Admins::SubjectQuery < ApplicationQuery
# 关键字
keyword = params[:keyword].to_s.strip
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR subjects.name LIKE :keyword'
sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR subjects.name LIKE :keyword'
subjects = subjects.joins(:user).where(sql, keyword: "%#{keyword}%")
end

View File

@@ -30,14 +30,14 @@ class Admins::UserQuery < ApplicationQuery
# 关键字检索
keyword = params[:keyword].to_s.strip.presence
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword'
sql = 'CONCAT_WS(lastname, firstname, nickname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword'
users = users.where(sql, keyword: "%#{keyword}%")
end
# 姓名
name = params[:name].to_s.strip.presence
if name.present?
users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%")
users = users.where('CONCAT_WS(lastname, firstname, nickname) LIKE :name', name: "%#{name}%")
end
# 单位ID

View File

@@ -53,10 +53,15 @@ class Projects::ListMyQuery < ApplicationQuery
q = projects.ransack(name_or_identifier_cont: params[:search])
scope = q.result.includes(:project_category, :project_language,:owner, :repository)
scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users)
sort = params[:sort_by] || "updated_on"
sort_direction = params[:sort_direction] || "desc"
scope.order("projects.#{sort} #{sort_direction}")
if params[:choosed].present? && params[:choosed].is_a?(Array)
scope.order("FIELD(id, #{params[:choosed].reverse.join(",")}) desc")
else
scope.order("projects.#{sort} #{sort_direction}")
end
end
end

View File

@@ -10,7 +10,7 @@ class UserQuery < ApplicationQuery
# 真实姓名
if name = strip_param(:name)
users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%")
users = users.where('LOWER(CONCAT_WS(users.lastname, users.firstname, users.nickname)) LIKE ?', "%#{name.downcase}%")
end
# 单位名称

View File

@@ -84,7 +84,7 @@ class Admins::ImportUserService < ApplicationService
if data.identity.to_i == 1
users = users.where(user_extensions: { student_id: data.student_id })
else
users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT(users.lastname,users.firstname) = ?', data.name)
users = users.where(user_extensions: { technical_title: data.technical_title }).where('CONCAT_WS(users.lastname,users.firstname,users.nickname) = ?', data.name)
end
users.first

View File

@@ -0,0 +1,41 @@
class Cache::PlatformFollowCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_follow_count
platform_follow_count
end
def reset
reset_platform_follow_count
platform_follow_count
end
private
def platform_follow_count_key
"platform-follow-count"
end
def platform_follow_count
$redis_cache.get(platform_follow_count_key).to_i
end
def set_platform_follow_count
if $redis_cache.exists(platform_follow_count_key)
$redis_cache.incrby(platform_follow_count_key, increment_count)
else
reset_platform_follow_count
end
end
def reset_platform_follow_count
$redis_cache.set(platform_follow_count_key, Watcher.where(watchable_type: 'User').count)
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformIssueCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_issue_count
platform_issue_count
end
def reset
reset_platform_issue_count
platform_issue_count
end
private
def platform_issue_count_key
"platform-issue-count"
end
def platform_issue_count
$redis_cache.get(platform_issue_count_key).to_i
end
def set_platform_issue_count
if $redis_cache.exists(platform_issue_count_key)
$redis_cache.incrby(platform_issue_count_key, increment_count)
else
reset_platform_issue_count
end
end
def reset_platform_issue_count
$redis_cache.set(platform_issue_count_key, Issue.count)
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformProjectCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_project_count
platform_project_count
end
def reset
reset_platform_project_count
platform_project_count
end
private
def platform_project_count_key
"platform-project-count"
end
def platform_project_count
$redis_cache.get(platform_project_count_key).to_i
end
def set_platform_project_count
if $redis_cache.exists(platform_project_count_key)
$redis_cache.incrby(platform_project_count_key, increment_count)
else
reset_platform_project_count
end
end
def reset_platform_project_count
$redis_cache.set(platform_project_count_key, Project.count)
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformProjectForkCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_project_fork_count
platform_project_fork_count
end
def reset
reset_platform_project_fork_count
platform_project_fork_count
end
private
def platform_project_fork_count_key
"platform-project-fork-count"
end
def platform_project_fork_count
$redis_cache.get(platform_project_fork_count_key).to_i
end
def set_platform_project_fork_count
if $redis_cache.exists(platform_project_fork_count_key)
$redis_cache.incrby(platform_project_fork_count_key, increment_count)
else
reset_platform_project_fork_count
end
end
def reset_platform_project_fork_count
$redis_cache.set(platform_project_fork_count_key, ForkUser.count)
end
end

View File

@@ -0,0 +1,57 @@
class Cache::PlatformProjectLanguagesCountService < ApplicationService
attr_reader :key, :increment_count
def initialize(key=nil, increment_count=0)
@key = key
@increment_count = increment_count
end
def call
set_platform_project_language_count
platform_project_language_count
end
def reset_by_key
reset_platform_project_language_count_by_key
platform_project_language_count
end
def reset
reset_platform_project_language_count
platform_project_language_count
end
private
def platform_project_language_count_key
"platform-project-language-count"
end
def platform_project_language_count
$redis_cache.hgetall(platform_project_language_count_key).transform_values(&:to_i)
end
def set_platform_project_language_count
if $redis_cache.hlen(platform_project_language_count_key) == 0
reset_platform_project_language_count
elsif $redis_cache.hget(platform_project_language_count_key, key).nil?
reset_platform_project_language_count_by_key
else
$redis_cache.hincrby(platform_project_language_count_key, key, increment_count)
end
end
def reset_platform_project_language_count_by_key
return if key.nil?
$redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count)
end
def reset_platform_project_language_count
Project.joins(:project_language).group("project_languages.name").count.each do |k, v|
$redis_cache.hset(platform_project_language_count_key, k, v)
end
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformProjectPraisesCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_project_praises_count
platform_project_praises_count
end
def reset
reset_platform_project_praises_count
platform_project_praises_count
end
private
def platform_project_praises_count_key
"platform-project-praises-count"
end
def platform_project_praises_count
$redis_cache.get(platform_project_praises_count_key).to_i
end
def set_platform_project_praises_count
if $redis_cache.exists(platform_project_praises_count_key)
$redis_cache.incrby(platform_project_praises_count_key, increment_count)
else
reset_platform_project_praises_count
end
end
def reset_platform_project_praises_count
$redis_cache.set(platform_project_praises_count_key, PraiseTread.where(praise_tread_object_type: "Project").count)
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformProjectWatchersCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_project_watchers_count
platform_project_watchers_count
end
def reset
reset_platform_project_watchers_count
platform_project_watchers_count
end
private
def platform_project_watchers_count_key
"platform-project-watchers-count"
end
def platform_project_watchers_count
$redis_cache.get(platform_project_watchers_count_key).to_i
end
def set_platform_project_watchers_count
if $redis_cache.exists(platform_project_watchers_count_key)
$redis_cache.incrby(platform_project_watchers_count_key, increment_count)
else
reset_platform_project_watchers_count
end
end
def reset_platform_project_watchers_count
$redis_cache.set(platform_project_watchers_count_key, Watcher.where(watchable_type: 'Project').count)
end
end

View File

@@ -0,0 +1,41 @@
class Cache::PlatformPullrequestCountService < ApplicationService
attr_reader :increment_count
def initialize(increment_count=0)
@increment_count = increment_count
end
def call
set_platform_pullrequest_count
platform_pullrequest_count
end
def reset
reset_platform_pullrequest_count
platform_pullrequest_count
end
private
def platform_pullrequest_count_key
"platform-pullrequest-count"
end
def platform_pullrequest_count
$redis_cache.get(platform_pullrequest_count_key).to_i
end
def set_platform_pullrequest_count
if $redis_cache.exists(platform_pullrequest_count_key)
$redis_cache.incrby(platform_pullrequest_count_key, increment_count)
else
reset_platform_pullrequest_count
end
end
def reset_platform_pullrequest_count
$redis_cache.set(platform_pullrequest_count_key, PullRequest.count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserFollowCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_follow_count
user_follow_count
end
def reset
reset_user_follow_count
user_follow_count
end
private
def user_follow_count_key
"user-follow-count-#{user.id}"
end
def user_follow_count
$redis_cache.get(user_follow_count_key).to_i
end
def set_user_follow_count
if $redis_cache.exists(user_follow_count_key)
$redis_cache.incrby(user_follow_count_key, increment_count)
else
reset_user_follow_count
end
end
def reset_user_follow_count
return if user.nil?
$redis_cache.set(user_follow_count_key, Watcher.where(watchable: user).count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserIssueCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_issue_count
user_issue_count
end
def reset
reset_user_issue_count
user_issue_count
end
private
def user_issue_count_key
"user-issue-count-#{user.id}"
end
def user_issue_count
$redis_cache.get(user_issue_count_key).to_i
end
def set_user_issue_count
if $redis_cache.exists(user_issue_count_key)
$redis_cache.incrby(user_issue_count_key, increment_count)
else
reset_user_issue_count
end
end
def reset_user_issue_count
return if user.nil?
$redis_cache.set(user_issue_count_key, Issue.where(author_id: user.id).count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserProjectCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_project_count
user_project_count
end
def reset
reset_user_project_count
user_project_count
end
private
def user_project_count_key
"user-project-count-#{user.id}"
end
def user_project_count
$redis_cache.get(user_project_count_key).to_i
end
def set_user_project_count
if $redis_cache.exists(user_project_count_key)
$redis_cache.incrby(user_project_count_key, increment_count)
else
reset_user_project_count
end
end
def reset_user_project_count
return if user.nil?
$redis_cache.set(user_project_count_key, user.projects.count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserProjectForkCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_project_fork_count
user_project_fork_count
end
def reset
reset_user_project_fork_count
user_project_fork_count
end
private
def user_project_fork_count_key
"user-project-fork-count-#{user.id}"
end
def user_project_fork_count
$redis_cache.get(user_project_fork_count_key).to_i
end
def set_user_project_fork_count
if $redis_cache.exists(user_project_fork_count_key)
$redis_cache.incrby(user_project_fork_count_key, increment_count)
else
reset_user_project_fork_count
end
end
def reset_user_project_fork_count
return if user.nil?
$redis_cache.set(user_project_fork_count_key, ForkUser.joins(:project).where(projects: {user_id: user.id}).count)
end
end

View File

@@ -0,0 +1,60 @@
class Cache::UserProjectLanguagesCountService < ApplicationService
attr_reader :user, :key, :increment_count
def initialize(user, key=nil, increment_count=0)
@user = user
@key = key
@increment_count = increment_count
end
def call
set_user_project_language_count
user_project_language_count
end
def reset_by_key
reset_user_project_language_count_by_key
user_project_language_count
end
def reset
reset_user_project_language_count
user_project_language_count
end
private
def user_project_language_count_key
"user-project-language-count-#{user.id}"
end
def user_project_language_count
$redis_cache.hgetall(user_project_language_count_key).transform_values(&:to_i)
end
def set_user_project_language_count
if $redis_cache.hlen(user_project_language_count_key) == 0
reset_user_project_language_count
elsif $redis_cache.hget(user_project_language_count_key, key).nil?
reset_user_project_language_count_by_key
else
$redis_cache.hincrby(user_project_language_count_key, key, increment_count)
end
end
def reset_user_project_language_count_by_key
return if user.nil?
return if key.nil?
$redis_cache.hset(user_project_language_count_key, key, user.projects.joins(:project_language).where(project_languages: {name: key}).count)
end
def reset_user_project_language_count
return if user.nil?
user.projects.joins(:project_language).group("project_languages.name").count.each do |k, v|
$redis_cache.hset(user_project_language_count_key, k, v)
end
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserProjectPraisesCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_project_praises_count
user_project_praises_count
end
def reset
reset_user_project_praises_count
user_project_praises_count
end
private
def user_project_praises_count_key
"user-project-praises-count-#{user.id}"
end
def user_project_praises_count
$redis_cache.get(user_project_praises_count_key).to_i
end
def set_user_project_praises_count
if $redis_cache.exists(user_project_praises_count_key)
$redis_cache.incrby(user_project_praises_count_key, increment_count)
else
reset_user_project_praises_count
end
end
def reset_user_project_praises_count
return if user.nil?
$redis_cache.set(user_project_praises_count_key, PraiseTread.where(praise_tread_object_type: 'Project', praise_tread_object_id: user.projects).count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserProjectWatchersCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_project_watchers_count
user_project_watchers_count
end
def reset
reset_user_project_watchers_count
user_project_watchers_count
end
private
def user_project_watchers_count_key
"user-project-watchers-count-#{user.id}"
end
def user_project_watchers_count
$redis_cache.get(user_project_watchers_count_key).to_i
end
def set_user_project_watchers_count
if $redis_cache.exists(user_project_watchers_count_key)
$redis_cache.incrby(user_project_watchers_count_key, increment_count)
else
reset_user_project_watchers_count
end
end
def reset_user_project_watchers_count
return if user.nil?
$redis_cache.set(user_project_watchers_count_key, Watcher.where(watchable_type: 'Project', watchable_id: user.projects).count)
end
end

View File

@@ -0,0 +1,43 @@
class Cache::UserPullrequestCountService < ApplicationService
attr_reader :user, :increment_count
def initialize(user, increment_count=0)
@user = user
@increment_count = increment_count
end
def call
set_user_pullrequest_count
user_pullrequest_count
end
def reset
reset_user_pullrequest_count
user_pullrequest_count
end
private
def user_pullrequest_count_key
"user-pullrequest-count-#{user.id}"
end
def user_pullrequest_count
$redis_cache.get(user_pullrequest_count_key).to_i
end
def set_user_pullrequest_count
if $redis_cache.exists(user_pullrequest_count_key)
$redis_cache.incrby(user_pullrequest_count_key, increment_count)
else
reset_user_pullrequest_count
end
end
def reset_user_pullrequest_count
return if user.nil?
$redis_cache.set(user_pullrequest_count_key, PullRequest.where(user_id: user.id).count)
end
end

View File

@@ -0,0 +1,96 @@
class Gitea::Accelerator::BaseService < ApplicationService
def post(url, params)
puts "[gitea] request params: #{params}"
puts "[gitea] access_username: #{access_username}"
puts "[gitea] access_password: #{access_password}"
conn.post do |req|
req.url full_url(url)
req.body = params.to_json
end
end
private
def conn
@client ||= begin
Faraday.new(url: domain) do |req|
req.request :url_encoded
req.headers['Content-Type'] = 'application/json'
req.response :logger # 显示日志
req.adapter Faraday.default_adapter
req.basic_auth(access_username, access_password)
end
end
@client
end
def base_url
accelerator["base_url"]
end
def domain
accelerator["domain"]
end
def api_url
[domain, base_url].join('')
end
def full_url(api_rest, action='post')
url = [api_url, api_rest].join('').freeze
url = action === 'get' ? url : URI.escape(url)
puts "[gitea] request url: #{url}"
url
end
def access_username
accelerator["access_key_id"]
end
def access_password
accelerator["access_key_secret"]
end
def access_uid
accelerator["access_admin_uid"]
end
def accelerator
Gitea.gitea_config[:accelerator]
end
def render_status(response)
puts "[gitea] response status: #{response.status}"
puts "[gitea] response body: #{response.body}"
case response.status
when 201
success
when 403
error('APIForbiddenError')
when 422
error('APIValidationError')
else
error("MigrateError")
end
end
def error(message)
{
status: :error,
message: message,
data: nil
}
end
def success(data=nil)
{
status: :success,
message: nil,
data: data
}
end
def check_accelerator!
accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank?
end
end

View File

@@ -1,4 +1,4 @@
class Gitea::Accelerator::MigrateService < ApplicationService
class Gitea::Accelerator::MigrateService < Gitea::Accelerator::BaseService
attr_reader :params
# params description:
@@ -36,8 +36,8 @@ class Gitea::Accelerator::MigrateService < ApplicationService
render_status(response)
end
private
private
def request_params
{
uid: access_uid,
@@ -52,97 +52,4 @@ class Gitea::Accelerator::MigrateService < ApplicationService
def url
"/repos/migrate".freeze
end
def post(url, params)
puts "[gitea] request params: #{params}"
puts "[gitea] access_username: #{access_username}"
puts "[gitea] access_password: #{access_password}"
conn.post do |req|
req.url full_url(url)
req.body = params.to_json
end
end
def conn
@client ||= begin
Faraday.new(url: domain) do |req|
req.request :url_encoded
req.headers['Content-Type'] = 'application/json'
req.response :logger # 显示日志
req.adapter Faraday.default_adapter
req.basic_auth(access_username, access_password)
end
end
@client
end
def base_url
accelerator["base_url"]
end
def domain
accelerator["domain"]
end
def api_url
[domain, base_url].join('')
end
def full_url(api_rest, action='post')
url = [api_url, api_rest].join('').freeze
url = action === 'get' ? url : URI.escape(url)
puts "[gitea] request url: #{url}"
url
end
def access_username
accelerator["access_key_id"]
end
def access_password
accelerator["access_key_secret"]
end
def access_uid
accelerator["access_admin_uid"]
end
def accelerator
Gitea.gitea_config[:accelerator]
end
def render_status(response)
puts "[gitea] response status: #{response.status}"
puts "[gitea] response body: #{response.body}"
case response.status
when 201
success
when 403
error('APIForbiddenError')
when 422
error('APIValidationError')
else
error("MigrateError")
end
end
def error(message)
{
status: :error,
message: message,
data: nil
}
end
def success(data=nil)
{
status: :success,
message: nil,
data: data
}
end
def check_accelerator!
accelerator.blank? || access_username.blank? || access_password.blank? || domain.blank?
end
end

View File

@@ -0,0 +1,31 @@
# Sync a mirrored repository
class Gitea::Accelerator::SyncMirroredService < Gitea::Accelerator::BaseService
attr_reader :repo, :token
# repo *
# name of the repo to sync
# example:
# Gitea::Accelerator::SyncMirroredService.call(repo.identifier)
def initialize(repo, token=nil)
@repo = repo
@token = token
end
def call
return error('[gitea:] accelerator config missing') if check_accelerator!
response = post(url, request_params)
{status: response.status}
end
private
def request_params
Hash.new.merge(token: token).compact
end
def url
"/repos/#{access_username}/#{repo}/mirror-sync".freeze
end
end

View File

@@ -0,0 +1,23 @@
class Gitea::User::HeadmapService < Gitea::ClientService
attr_reader :start_time, :end_time, :username
def initialize(username, start_time, end_time)
@username = username
@start_time = start_time
@end_time = end_time
end
def call
response = get(url, params)
render_response(response)
end
private
def params
Hash.new.merge(start: start_time, end: end_time)
end
def url
"/users/#{username}/heatmap".freeze
end
end

View File

@@ -34,7 +34,7 @@ class Projects::TransferService < ApplicationService
def update_visit_teams
if new_owner.is_a?(Organization)
# 为包含组织所有项目的团队创建项目访问权限
new_owner.build_permit_team_projects(project.id)
new_owner.build_permit_team_projects!(project.id)
else
project.team_projects.each(&:destroy!)
end

View File

@@ -1,4 +1,10 @@
json.name issue.try(:subject)
json.issue_type issue.issue_type == "1" ? "普通" : "悬赏"
json.status_id issue.try(:status_id)
json.issue_status issue.issue_status.try(:name)
json.priority issue.priority.try(:name)
json.priority_id issue.try(:priority_id)
json.version issue.version.try(:name)
json.created_at format_time(issue.try(:created_on))
json.updated_at format_time(issue.try(:updated_on))
json.assign_user_name issue&.get_assign_user.try(:show_real_name)

View File

@@ -0,0 +1,17 @@
json.id trend.id
json.trend_type trend.trend_type
json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}")
json.trend_id trend.trend_id
json.user_name trend.user.try(:show_real_name)
json.user_login trend.user.login
json.user_avatar url_to_avatar(trend.user)
json.action_time time_from_now(trend.created_at)
if trend.trend_type == "Issue"
json.partial! "issues/simple_issue_item", locals: {issue: trend.trend}
elsif trend.trend_type == "VersionRelease"
json.partial! "version_releases/simple_version_release", locals: {version: trend.trend}
else
json.name trend.trend&.title
json.created_at format_time(trend.trend&.created_at)
end

View File

@@ -9,25 +9,9 @@ json.limit @limit
json.project_trends_size @project_trends_size
json.project_trends do
json.array! @project_trends.to_a.each do |trend|
json.id trend.id
json.trend_type trend.trend_type
json.action_type l("trend.#{trend.action_type}") + l("trend.#{trend.trend_type}")
json.trend_id trend.trend_id
json.user_name trend.user.try(:show_real_name)
json.user_login trend.user.login
json.user_avatar url_to_avatar(trend.user)
if trend.trend_type == "Issue"
json.partial! "issues/simple_issue_item", locals: {issue: trend.trend}
elsif trend.trend_type == "VersionRelease"
json.partial! "version_releases/simple_version_release", locals: {version: trend.trend}
else
json.name trend.trend.title
json.created_at format_time(trend.trend.created_at)
end
#后续需要天际pullrequest 和 版本的内容
json.partial! "detail", trend: trend
end
end

View File

@@ -5,6 +5,9 @@ json.name project.name
json.description Nokogiri::HTML(project.description).text
json.visits project.visits
json.praises_count project.praises_count.to_i
json.watchers_count project.watchers_count.to_i
json.issues_count project.issues_count.to_i
json.pull_requests_count project.pull_requests_count.to_i
json.forked_count project.forked_count.to_i
json.is_public project.is_public
json.mirror_url project.repository&.mirror_url
@@ -14,6 +17,7 @@ json.time_ago time_from_now(project.updated_on)
json.forked_from_project_id project.forked_from_project_id
json.open_devops project.open_devops?
json.platform project.platform
json.is_pinned project.has_pinned_users.include?(current_user)
json.author do
if project.educoder?
project_educoder = project.project_educoder

View File

@@ -48,7 +48,7 @@ if @result[:repo]
json.size replace_bytes_to_b(number_to_human_size(@result[:repo]['size'].to_i*1024))
json.ssh_url @result[:repo]['ssh_url']
json.clone_url @result[:repo]['clone_url']
json.default_branch @result[:repo]['default_branch']
json.default_branch @project.educoder? ? "master" : @result[:repo]['default_branch']
json.empty @result[:repo]['empty']
json.full_name @result[:repo]['full_name']
json.private @result[:repo]['private']

View File

@@ -12,4 +12,5 @@ json.permission render_permission(current_user, @project)
json.is_transfering @project.is_transfering
json.transfer do
json.partial! "/users/user_simple", locals: {user: @project&.applied_transfer_project&.owner}
end
end
json.is_pinned @project.has_pinned_users.include?(current_user)

View File

@@ -1,7 +1,20 @@
json.user_id user.id
json.login user.login
json.name user.full_name
json.username @user.full_name
json.real_name @user.real_name
json.grade user.grade
json.identity user&.user_extension&.identity
# json.email user.mail # 邮箱原则上不暴露的,如果实在需要的话只能对某些具体的接口公开
json.image_url url_to_avatar(user)
json.gender @user.gender
json.login @user.login
json.user_id @user.id
json.image_url url_to_avatar(@user)
json.admin @user.admin?
json.user_identity @user.identity
json.is_watch current_user&.watched?(@user)
json.watched_count @user.fan_count #粉丝
json.watching_count @user.follow_count #关注数
json.created_time format_time(@user.created_on)
json.email @user.show_email ? @user.mail : nil
json.province @user.show_location ? @user.province : nil
json.city @user.show_location ? @user.city : nil
json.custom_department @user.show_department ? @user.custom_department : nil
json.description @user.description

View File

@@ -3,7 +3,7 @@ json.format_time target.created_at.strftime("%Y-%m-%d")
json.name user.try(:show_real_name)
json.login user.try(:login)
json.image_url url_to_avatar(user)
json.is_current_user current_user.try(:id) == target.user_id
json.is_current_user current_user.try(:id) == user.id
json.is_watch current_user&.watched?(user)

View File

@@ -1,5 +1,6 @@
json.username @user.full_name
json.real_name @user.real_name
json.gender @user.gender
json.login @user.login
json.user_id @user.id
json.image_url url_to_avatar(@user)
@@ -14,3 +15,9 @@ json.profile_completed @user.profile_completed?
json.professional_certification @user.professional_certification
json.devops_step @user.devops_step
json.ci_certification @user.ci_certification?
json.email @user.mail
json.province @user.province
json.city @user.city
json.custom_department @user.custom_department
json.description @user.description
json.(@user, :show_email, :show_department, :show_location)

View File

@@ -0,0 +1,5 @@
json.total_contributions @headmaps.collect{|map| map["contributions"]}.reduce(0, :+)
json.headmaps @headmaps.each do |map|
json.date Time.at(map["timestamp"].to_i).strftime("%Y-%m-%d")
json.contributions map["contributions"]
end

View File

@@ -0,0 +1,7 @@
json.total_count @is_pinned_projects.total_count
json.projects @is_pinned_projects.each do |project|
json.partial! "projects/project_detail", project: project&.project
json.id project.id
json.position project.position
json.project_id project.project_id
end

View File

@@ -0,0 +1,4 @@
json.total_count @project_trends.total_count
json.project_trends @project_trends.each do |trend|
json.partial! "project_trends/detail", trend: trend
end

View File

@@ -1,15 +1,4 @@
# json.partial! 'users/user', locals: { user: @user }
json.username @user.full_name
json.real_name @user.real_name
json.login @user.login
json.user_id @user.id
json.image_url url_to_avatar(@user)
json.admin @user.admin?
json.user_identity @user.identity
json.is_watch current_user&.watched?(@user)
json.watched_count @user.fan_count #粉丝
json.watching_count @user.follow_count #关注数
json.partial! 'users/user', locals: { user: @user }
json.undo_messages @waiting_applied_messages.size
json.undo_transfer_projects @common_applied_transfer_projects.size
json.undo_events @undo_events
@@ -17,4 +6,10 @@ json.user_composes_count @user_composes_count
json.user_org_count @user_org_count
json.common_projects_count @projects_common_count
json.mirror_projects_count @projects_mirrior_count
json.sync_mirror_projects_count @projects_sync_mirrior_count
json.sync_mirror_projects_count @projects_sync_mirrior_count
json.created_time format_time(@user.created_on)
json.email @user.show_email ? @user.mail : nil
json.province @user.show_location ? @user.province : nil
json.city @user.show_location ? @user.city : nil
json.custom_department @user.show_department ? @user.custom_department : nil
json.description @user.description

View File

@@ -0,0 +1,19 @@
json.platform do
json.influence @platform_influence
json.contribution @platform_contribution
json.activity @platform_activity
json.experience @platform_experience
json.language @platform_language
# json.languages_percent @platform_languages_percent
# json.each_language_score @platform_each_language_score
end
json.user do
json.influence @influence
json.contribution @contribution
json.activity @activity
json.experience @experience
json.language @language
json.languages_percent @languages_percent
json.each_language_score @each_language_score
end

View File

@@ -0,0 +1,19 @@
json.total_projects_count @full_member_projects_count
json.role do
json.owner do
json.count @owner_projects_count
json.percent (@owner_projects_count.to_f/@full_member_projects_count).round(2)
end
json.manager do
json.count @manager_projects_count
json.percent (@manager_projects_count.to_f/@full_member_projects_count).round(2)
end
json.developer do
json.count @developer_projects_count
json.percent (@developer_projects_count.to_f/@full_member_projects_count).round(2)
end
json.reporter do
json.count @reporter_projects_count
json.percent (@reporter_projects_count.to_f/@full_member_projects_count).round(2)
end
end

View File

@@ -0,0 +1 @@
json.partial! 'users/user', locals: { user: @user }

View File

@@ -1,7 +1,7 @@
json.count @watchers_count
json.users do
json.array! @watchers do |watcher|
json.partial! "/users/watch_user_detail", locals: {target: watcher, user: watcher.watchable}
json.partial! "/users/watch_user_detail", target: watcher, user: watcher.watchable
end
# json.partial! "/users/watch_user_detail", collection: @watchers, as: :target
end