Compare commits
121 Commits
master
...
standalone
Author | SHA1 | Date |
---|---|---|
|
95f49450b0 | |
|
bcf0b376a9 | |
|
81a5adb21a | |
|
b6de7fa96b | |
|
01ef87f5a3 | |
|
a35537694c | |
|
2229c732ca | |
|
532b924ff1 | |
|
16a71a383b | |
|
7d67defa24 | |
|
41515575f1 | |
|
f4248ec14b | |
|
9544a5b22d | |
|
9cf4cc290c | |
|
e37d76d972 | |
|
c18d1d2ce4 | |
|
40576e321f | |
|
f9e7b92386 | |
|
40955f5a99 | |
|
cece63286e | |
|
debefe2e7c | |
|
ad2f42bed6 | |
|
473b9e3dfd | |
|
655bb7bb4e | |
|
da48040d2c | |
|
732a3a1405 | |
|
31e4d73e2a | |
|
bd3dd5df4a | |
|
85b55619c6 | |
|
9d968ac5db | |
|
a90bed0b8f | |
|
4151b3564f | |
|
bff04758b8 | |
|
7f386622a3 | |
|
9d8600eb1c | |
|
981dde45ef | |
|
b02cf8fe79 | |
|
44c8d0be7c | |
|
4afce7809d | |
|
10c05896fc | |
|
d260fcfe35 | |
|
d286502224 | |
|
cabc9775bc | |
|
8c9f6d6175 | |
|
0ae4f8decd | |
|
a86372dc16 | |
|
3eebf61f03 | |
|
cf6dc3a9b4 | |
|
2a0ce2972a | |
|
8cab37587e | |
|
542fe0b60c | |
|
bb720d20c1 | |
|
6bcdc20500 | |
![]() |
5faf040862 | |
|
991a421b67 | |
![]() |
74f928bab2 | |
|
9cb7a22e52 | |
|
6a7174781c | |
|
880f547b3b | |
|
f97ad21af5 | |
|
5230064b29 | |
|
8fffa5530c | |
|
02df11cc64 | |
|
ba2a76de8c | |
|
f1bf41c7f6 | |
|
1a282dc925 | |
|
829e6bfe02 | |
|
c3754f65cd | |
|
16a64027f1 | |
|
e6eea663a9 | |
|
52b46f4b89 | |
![]() |
e7795faa22 | |
|
831576d4aa | |
![]() |
2b9e53565a | |
|
76d3c29c42 | |
![]() |
346b815e0a | |
|
7496a4bdd6 | |
![]() |
470064ecd5 | |
|
974213ff59 | |
![]() |
b52aa0633e | |
|
76545cf72f | |
|
14350f6812 | |
![]() |
0bc702b957 | |
|
d5b0fccf03 | |
![]() |
2ff38ad402 | |
|
63593535a7 | |
![]() |
f767d95730 | |
|
e317fafb89 | |
![]() |
27d73f0c11 | |
|
a8f06eb022 | |
|
6598eb6b76 | |
|
c97188aff8 | |
|
7d466217c7 | |
|
d86d7f5d3e | |
![]() |
a2ab42f392 | |
|
a3517e651f | |
![]() |
3e859e4469 | |
|
74706ab7a2 | |
![]() |
8fa20c7f6b | |
|
f96bcfa162 | |
|
145463f967 | |
|
6a6698bc74 | |
|
41cbeae2f7 | |
|
9645f38e31 | |
![]() |
fa26098426 | |
|
6c937e6af6 | |
![]() |
ef06a808a9 | |
|
6d51061f49 | |
![]() |
4eaf5aada2 | |
|
fb461b2fe6 | |
![]() |
045d324809 | |
|
e03e011f18 | |
![]() |
055e916d08 | |
|
37e28fdf2e | |
![]() |
1a755048bb | |
|
fcabd83a9d | |
![]() |
387f33b2b0 | |
|
c0e6720cd4 | |
![]() |
737b6bc18f | |
|
616e99cc86 | |
![]() |
ee47f29264 |
|
@ -292,6 +292,7 @@ class AccountsController < ApplicationController
|
|||
UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip)
|
||||
user.update_column(:last_login_on, Time.now)
|
||||
session[:"#{default_yun_session}"] = user.id
|
||||
UserOnline.login(user.id)
|
||||
Rails.logger.info("#########_____session_default_yun_session__________###############{default_yun_session}")
|
||||
# 注册完成后有一天的试用申请(先去掉)
|
||||
# UserDayCertification.create(user_id: user.id, status: 1)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Admins::DashboardsController < Admins::BaseController
|
||||
before_action :require_business
|
||||
|
||||
def index
|
||||
# 用户活跃数
|
||||
day_user_ids = CommitLog.where(created_at: today).pluck(:user_id).uniq
|
||||
|
@ -65,17 +67,16 @@ class Admins::DashboardsController < Admins::BaseController
|
|||
CommitLog.count
|
||||
end
|
||||
|
||||
@subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数"]
|
||||
@subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload"]
|
||||
@subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count]
|
||||
@subject_name = ["用户数", "项目数", "组织数", "Issue数", "Issue评论数", "PR数", "Commit数", "在线用户数"]
|
||||
@subject_icon = ["fa-user","fa-git", "fa-sitemap", "fa-warning", "fa-comments", "fa-share-alt", "fa-upload", "fa-user"]
|
||||
@subject_data = [@user_count, @project_count, @organization_count, @issue_count, @comment_count, @pr_count, @commit_count, UserOnline.count]
|
||||
|
||||
if EduSetting.get("open_baidu_tongji").to_s == "true"
|
||||
tongji_service = Baidu::TongjiService.new
|
||||
@access_token = tongji_service.access_token
|
||||
Rails.logger.info "baidu_tongji_auth access_token ===== #{@access_token}"
|
||||
# @overview_data = tongji_service.api_overview
|
||||
last_date = DailyPlatformStatistic.order(:date).last || Time.now
|
||||
start_date = last_date.date
|
||||
start_date = DailyPlatformStatistic.order(:date).last.try(:date) || Time.now.to_date
|
||||
end_date = Time.now
|
||||
if @access_token.present?
|
||||
@overview_data = Rails.cache.fetch("dashboardscontroller:baidu_tongji:overview_data", expires_in: 10.minutes) do
|
||||
|
|
|
@ -23,7 +23,7 @@ class Admins::LaboratorySettingsController < Admins::BaseController
|
|||
|
||||
def form_params
|
||||
params.permit(:identifier, :name,
|
||||
:nav_logo, :login_logo, :tab_logo, :oj_banner,
|
||||
:nav_logo, :login_logo, :tab_logo, :pm_logo, :oj_banner,
|
||||
:subject_banner, :course_banner, :competition_banner, :moop_cases_banner,
|
||||
:footer, navbar: %i[name link hidden index])
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::OrganizationsController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :finder_org, except: [:index]
|
||||
|
||||
def index
|
||||
|
@ -30,9 +30,11 @@ class Admins::OrganizationsController < Admins::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
data_bank = @org.attributes.to_json
|
||||
@org.destroy!
|
||||
Admins::DeleteOrganizationService.call(@org.login)
|
||||
UserAction.create(action_id: @org.id, action_type: "DestroyOrganization", user_id: current_user.id, :ip => request.remote_ip, data_bank: @org.attributes.to_json)
|
||||
data_bank = @org.attributes.to_json
|
||||
UserAction.create(action_id: @org.id, action_type: "DestroyOrganization", user_id: current_user.id, :ip => request.remote_ip, data_bank: data_bank)
|
||||
render_delete_success
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::ProjectCategoriesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :get_category, only: [:edit,:update, :destroy]
|
||||
before_action :validate_names, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::ProjectIgnoresController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :set_ignore, only: [:edit,:update, :destroy,:show]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::ProjectLanguagesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :get_language, only: [:edit,:update, :destroy]
|
||||
before_action :validate_names, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::ProjectLicensesController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :set_license, only: [:edit,:update, :destroy,:show]
|
||||
# before_action :validate_params, only: [:create, :update]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::ProjectsController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :find_project, only: [:edit, :update]
|
||||
|
||||
def index
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Admins::UsersController < Admins::BaseController
|
||||
before_action :require_admin
|
||||
before_action :require_business
|
||||
before_action :finder_user, except: [:index]
|
||||
|
||||
def index
|
||||
|
|
|
@ -18,10 +18,9 @@ class Api::Pm::DashboardsController < Api::Pm::BaseController
|
|||
return render_error('请输入正确的pm_issue_types.') if params[:pm_issue_types].blank?
|
||||
pm_project_ids = params[:pm_project_ids].split(",") rescue []
|
||||
pm_issue_types = params[:pm_issue_types].split(",") rescue []
|
||||
@all_issues = Issue.where(pm_project_id: pm_project_ids, pm_issue_type: pm_issue_types)
|
||||
@all_issues = Issue.where(pm_project_id: pm_project_ids, pm_issue_type: pm_issue_types).order(created_on: :desc)
|
||||
@issues = @all_issues.joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'})
|
||||
@issues = @issues.where.not(status_id: 5) if params[:category] == "opened"
|
||||
|
||||
@issues = kaminari_paginate(@issues.distinct.pm_includes)
|
||||
@my_assign_requirements_count = @all_issues.where(pm_issue_type: 1).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'}).size
|
||||
@my_assign_tasks_count = @all_issues.where(pm_issue_type: 2).joins(:issue_participants).where(issue_participants: {participant_id: current_user.id, participant_type: 'assigned'}).size
|
||||
|
|
|
@ -177,7 +177,7 @@ class Api::Pm::IssuesController < Api::Pm::BaseController
|
|||
issue.fake_id = row[0]
|
||||
issue.subject = row[1]
|
||||
issue.description = row[2]
|
||||
author = User.find_by(login: row[3])
|
||||
author = User.find_by(login: row[3]) || User.where(admin: true).first
|
||||
issue.user = author
|
||||
issue.created_on = row[4]
|
||||
changer = User.find_by(login: row[5])
|
||||
|
|
|
@ -5,16 +5,18 @@ class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
|
|||
return render_error('请输入正确的用户ID.') if params[:user_id].blank?
|
||||
@all_issues = Issue.joins(:issue_participants).where(issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||
@all_issues = @all_issues.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s).distinct
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (Date.today.beginning_of_week+1.week).to_s, (Date.today.end_of_week+1.week).to_s).distinct
|
||||
@next_week_all_issues = @next_week_all_issues.order('created_on desc')
|
||||
@weekly_begin_date = params[:weekly_begin_date].to_time || Date.today.beginning_of_week rescue Date.today.beginning_of_week
|
||||
@weekly_end_date = params[:weekly_end_date].to_time || Date.today.end_of_week rescue Date.today.end_of_week
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date.to_s, @weekly_end_date.to_s).distinct
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc').pm_includes
|
||||
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (@weekly_begin_date+1.week).to_s, (@weekly_end_date+1.week).to_s).distinct
|
||||
@next_week_all_issues = @next_week_all_issues.order('created_on desc').pm_includes
|
||||
@this_week_requirement_issues = @this_week_all_issues.where(pm_issue_type: 1)
|
||||
@this_week_task_issues = @this_week_all_issues.where(pm_issue_type: 2)
|
||||
@this_week_bug_issues = @this_week_all_issues.where(pm_issue_type: 3)
|
||||
@close_requirement_issues = @this_week_requirement_issues.where(status_id: [3,5])
|
||||
@close_task_issues = @this_week_task_issues.where(status_id: [3,5])
|
||||
@close_bug_issues = @this_week_bug_issues.where(status_id: [3,5])
|
||||
@close_requirement_issues = @this_week_requirement_issues.where(status_id: [3,5]).pm_includes
|
||||
@close_task_issues = @this_week_task_issues.where(status_id: [3,5]).pm_includes
|
||||
@close_bug_issues = @this_week_bug_issues.where(status_id: [3,5]).pm_includes
|
||||
this_week_page = params[:this_week_page] || 1
|
||||
this_week_limit = params[:this_week_limit] || 15
|
||||
@this_week_all_issues = @this_week_all_issues.page(this_week_page).per(this_week_limit)
|
||||
|
@ -27,7 +29,9 @@ class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
|
|||
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
@all_issues = @all_issues.where(pm_project_id: params[:pm_project_ids].split(",")) if params[:pm_project_ids].present?
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s)
|
||||
@weekly_begin_date = params[:weekly_begin_date] || Date.today.beginning_of_week.to_s
|
||||
@weekly_end_date = params[:weekly_end_date] || Date.today.end_of_week.to_s
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date, @weekly_end_date)
|
||||
@this_week_all_issues_group_count = @this_week_all_issues.group(:pm_project_id).count
|
||||
data = {}
|
||||
@this_week_all_issues_group_count.keys.each do |pm_project_id|
|
||||
|
@ -55,22 +59,40 @@ class Api::Pm::WeeklyIssuesController < Api::Pm::BaseController
|
|||
|
||||
def group_issues
|
||||
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
root_id = params[:root_id] || -1
|
||||
@weekly_begin_date = params[:weekly_begin_date] || Date.today.beginning_of_week.to_s
|
||||
@weekly_end_date = params[:weekly_end_date] || Date.today.end_of_week.to_s
|
||||
@all_issues = Issue.none
|
||||
if root_id.to_i == -1
|
||||
@all_issues = Issue.where(root_id: nil, enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
elsif root_id.to_i.positive?
|
||||
@all_issues = Issue.where(root_id: root_id, enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
else
|
||||
@all_issues = Issue.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
end
|
||||
@all_issues = @all_issues.where(pm_project_id: params[:pm_project_ids].split(",")) if params[:pm_project_ids].present?
|
||||
@all_issues = @all_issues.where(pm_issue_type: params[:pm_issue_type].to_i) if params[:pm_issue_type].present?
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s)
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date, @weekly_end_date)
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc').pm_includes
|
||||
@this_week_all_issues = kaminari_paginate(@this_week_all_issues)
|
||||
end
|
||||
def personal_issues
|
||||
@enterprise_identifier = params[:enterprise_identifier] || ''
|
||||
return render_error('请输入正确的用户ID.') if params[:user_id].blank?
|
||||
@all_issues = Issue.joins(:issue_participants).where(issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||
@weekly_begin_date = params[:weekly_begin_date] || Date.today.beginning_of_week.to_s
|
||||
@weekly_end_date = params[:weekly_end_date] || Date.today.end_of_week.to_s
|
||||
root_id = params[:root_id] || -1
|
||||
@all_issues = Issue.none
|
||||
if root_id.to_i == -1
|
||||
@all_issues = Issue.joins(:issue_participants).where(root_id: nil, issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||
else
|
||||
@all_issues = Issue.joins(:issue_participants).where(root_id: root_id, issue_participants: {participant_id: params[:user_id], participant_type: ['assigned']})
|
||||
end
|
||||
@all_issues = @all_issues.where(enterprise_identifier: @enterprise_identifier, pm_issue_type: [1,2,3])
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", Date.today.beginning_of_week.to_s, Date.today.end_of_week.to_s).distinct
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc')
|
||||
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (Date.today.beginning_of_week+1.week).to_s, (Date.today.end_of_week+1.week).to_s).distinct
|
||||
@next_week_all_issues = @next_week_all_issues.order('created_on desc')
|
||||
@this_week_all_issues = @all_issues.where("due_date >= ? and start_date <= ?", @weekly_begin_date, @weekly_end_date).distinct
|
||||
@this_week_all_issues = @this_week_all_issues.order('created_on desc').pm_includes
|
||||
@next_week_all_issues = @all_issues.where("due_date >= ? and start_date <=?", (@weekly_begin_date.to_date+1.week).to_s, (@weekly_end_date.to_date+1.week).to_s).distinct
|
||||
@next_week_all_issues = @next_week_all_issues.order('created_on desc').pm_includes
|
||||
this_week_page = params[:this_week_page] || 1
|
||||
this_week_limit = params[:this_week_limit] || 15
|
||||
@this_week_all_issues = @this_week_all_issues.page(this_week_page).per(this_week_limit)
|
||||
|
|
|
@ -37,6 +37,11 @@ class Api::V1::BaseController < ApplicationController
|
|||
params.fetch(:page, 1)
|
||||
end
|
||||
|
||||
def load_organization
|
||||
@organization = Organization.find_by(login: params[:owner]) || Organization.find_by(id: params[:owner])
|
||||
return render_not_found("组织不存在") if @organization.nil?
|
||||
end
|
||||
|
||||
# 具有对仓库的管理权限
|
||||
def require_manager_above
|
||||
@project = load_project
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
class Api::V1::Organizations::ProjectsController < Api::V1::BaseController
|
||||
before_action :load_organization
|
||||
|
||||
def index
|
||||
public_projects_sql = @organization.projects.where(is_public: true).to_sql
|
||||
private_projects_sql = @organization.projects
|
||||
.where(is_public: false)
|
||||
.joins(team_projects: {team: :team_users})
|
||||
.where(team_users: {user_id: current_user.id}).to_sql
|
||||
@projects = Project.from("( #{ public_projects_sql} UNION #{ private_projects_sql } ) AS projects")
|
||||
# 表情处理
|
||||
keywords = params[:search].to_s.each_char.select { |c| c.bytes.first < 240 }.join('')
|
||||
@projects = @projects.where(is_public: params[:is_public]) if params[:is_public].present?
|
||||
@projects = @projects.where(id: params[:pm_project_repository_ids].split(',')) if params[:pm_project_repository_ids].present?
|
||||
@projects = @projects.where.not(id: params[:exclude_ids].to_s.split(",")) if params[:exclude_ids].present?
|
||||
@projects = @projects.where(project_type: ['mirror', 'common']).where("gpid is not null") if params[:actived].present?
|
||||
@projects = @projects.ransack(name_or_identifier_cont: keywords).result if params[:search].present?
|
||||
@projects = @projects.includes(:owner).order("projects.#{sort} #{sort_direction}")
|
||||
@projects = kaminari_paginate(@projects)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_organization
|
||||
@organization = Organization.find_by(login: params[:owner]) || Organization.find_by(id: params[:owner])
|
||||
return render_not_found("组织不存在") if @organization.nil?
|
||||
return render_forbidden("没有查看组织的权限") if org_limited_condition || org_privacy_condition
|
||||
end
|
||||
|
||||
def org_limited_condition
|
||||
@organization.organization_extension.limited? && !current_user.logged?
|
||||
end
|
||||
|
||||
def org_privacy_condition
|
||||
return false if current_user.admin?
|
||||
@organization.organization_extension.privacy? && @organization.organization_users.where(user_id: current_user.id).blank?
|
||||
end
|
||||
|
||||
def sort
|
||||
Project.column_names.include?(params[:sort_by]) ? params[:sort_by] : 'updated_on'
|
||||
end
|
||||
|
||||
def sort_direction
|
||||
%w(desc asc).include?(params[:sort_direction]) ? params[:sort_direction] : 'desc'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,42 @@
|
|||
class Api::V1::Organizations::SyncRepositoriesController < Api::V1::BaseController
|
||||
before_action :load_organization, only: [:create]
|
||||
|
||||
def create
|
||||
return render_error("请输入正确的外部组织login") unless params[:external_login].present?
|
||||
# 拉取外部组织仓库列表
|
||||
url = URI("https://api.github.com/orgs/#{params[:external_login]}/repos?page=#{params[:page]}&per_page=#{params[:limit]}")
|
||||
https = Net::HTTP.new(url.host, url.port)
|
||||
https.use_ssl = true
|
||||
request = Net::HTTP::Get.new(url)
|
||||
request["Authorization"] = "Bearer #{params[:external_token]}"
|
||||
response = https.request(request)
|
||||
if response.code == "200"
|
||||
repos = JSON.parse(response.body)
|
||||
repos.each do |repo|
|
||||
# 检查是否已经存在该仓库
|
||||
@project = @organization.projects.find_by(identifier: repo["name"])
|
||||
if @project.present?
|
||||
if @project.repository.mirror.failed?
|
||||
@project.destroy!
|
||||
mirror_params = {name: repo["name"], user_id: @organization.id, description: repo["description"], repository_name: repo["name"], auth_token: params[:external_token], clone_addr: repo["clone_url"]}
|
||||
@project = ::Projects::MigrateService.call(current_user, mirror_params)
|
||||
end
|
||||
@project.update_column(:created_on, repo['created_at'].to_time)
|
||||
@project.update_column(:updated_on, repo['updated_at'].to_time)
|
||||
next
|
||||
else
|
||||
mirror_params = {name: repo["name"], user_id: @organization.id, description: repo["description"], repository_name: repo["name"], auth_token: params[:external_token], clone_addr: repo["clone_url"]}
|
||||
@project = ::Projects::MigrateService.call(current_user, mirror_params)
|
||||
@project.update_column(:created_on, repo['created_at'].to_time)
|
||||
@project.update_column(:updated_on, repo['updated_at'].to_time)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def sync_repository_params
|
||||
params.permit(:external_token)
|
||||
end
|
||||
|
||||
end
|
|
@ -58,4 +58,15 @@ class Api::V1::Projects::Actions::RunsController < Api::V1::Projects::Actions::B
|
|||
redirect_to file_path
|
||||
end
|
||||
|
||||
def cancel
|
||||
return render_error("请输入正确的流水线记录ID!") if params[:run_id].blank?
|
||||
http = Gitea::Api::Hat::Http.new($gitea_hat_client.config)
|
||||
gitea_result = http.post("/repos/#{@project&.owner&.login}/#{@project&.identifier}/actions/runs/#{params[:run_id]}/cancel") rescue nil
|
||||
if gitea_result
|
||||
render_ok
|
||||
else
|
||||
render_error("停止流水线任务失败")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -148,7 +148,7 @@ class Api::V1::Projects::PipelinesController < Api::V1::BaseController
|
|||
interactor = Gitea::DeleteFileInteractor.call(current_user.gitea_token, @owner.login, del_content_params(sha).merge(identifier: @project.identifier))
|
||||
tip_exception(interactor.error) unless interactor.success?
|
||||
end
|
||||
Gitea::ActionRun.where(repo_id: @pipeline.project.gpid).destroy_all
|
||||
Gitea::ActionRun.where(repo_id: @pipeline.project.gpid, workflow_id: "#{@pipeline.pipeline_name}.yml").destroy_all
|
||||
@pipeline.destroy!
|
||||
end
|
||||
render_ok
|
||||
|
|
|
@ -6,13 +6,31 @@ class Api::V1::Projects::Pulls::PullsController < Api::V1::BaseController
|
|||
@pulls = kaminari_paginate(@pulls)
|
||||
end
|
||||
|
||||
before_action :load_pull_request, only: [:show, :files]
|
||||
before_action :load_pull_request, only: [:show, :reopen, :files]
|
||||
|
||||
def show
|
||||
@result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token)
|
||||
@last_review = @pull_request.reviews.order(created_at: :desc).take
|
||||
end
|
||||
|
||||
def reopen
|
||||
can_merge = @project&.pull_requests.where(head: @pull_request.head, base: @pull_request.base, status: 0, is_original: @pull_request.is_original, fork_project_id: @pull_request.fork_project_id)
|
||||
if can_merge.present?
|
||||
render json: {
|
||||
status: -1,
|
||||
redirect_url:"/#{@project.owner.login}/#{@project.identifier}/pulls/#{can_merge.first.gitea_number}",
|
||||
message: "在这些分支之间的合并请求已存在",
|
||||
}
|
||||
else
|
||||
@result_object = Api::V1::Projects::Pulls::ReopenService.call(@project, @pull_request, current_user)
|
||||
if @result_object
|
||||
render_ok
|
||||
else
|
||||
render_error("合并请求重新打开失败!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def files
|
||||
if params[:filepath].present?
|
||||
@result_object = $gitea_hat_client.get_repos_pulls_files_by_owner_repo_index_filepath(@project&.owner.login, @project&.identifier, @pull_request.gitea_number, CGI.escape(params[:filepath]), {query: {token: current_user&.gitea_token}})
|
||||
|
|
|
@ -41,24 +41,13 @@ class Api::V1::SonarqubesController < Api::V1::BaseController
|
|||
puts %Q{\033[33m [warning] soanrqube config or configuration.yml missing,
|
||||
please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m}
|
||||
end
|
||||
|
||||
sonar_content = build_sonar_content(params[:owner], @project.id, languages_precentagable.keys)
|
||||
sonar_scanner_content = {
|
||||
filepath: '.gitea/workflows/SonarScanner.yaml',
|
||||
branch: params[:branch],
|
||||
new_branch: nil,
|
||||
content: "
|
||||
on:
|
||||
# Trigger analysis when pushing to your main branches, and when creating a pull request.
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
- develop
|
||||
- 'releases/**'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
name: Main Workflow
|
||||
name: Sonar Scanner
|
||||
jobs:
|
||||
sonarqube:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -66,10 +55,22 @@ class Api::V1::SonarqubesController < Api::V1::BaseController
|
|||
- uses: #{checkout_url}
|
||||
with:
|
||||
# Disabling shallow clones is recommended for improving the relevancy of reporting
|
||||
fetch-depth: 0
|
||||
fetch-depth: 1
|
||||
single-branch: true
|
||||
- name: curl doxygen
|
||||
run: |
|
||||
curl -X GET #{doxygen_url}/generate?repo=#{@project.repository.url}
|
||||
|
||||
- name: new properties
|
||||
run: |
|
||||
cat <<EOF > sonar-project.properties
|
||||
#{sonar_content}
|
||||
EOF
|
||||
|
||||
- name: new build_tmp_folder
|
||||
run: |
|
||||
mkdir build_tmp_folder
|
||||
|
||||
- name: SonarQube Scan
|
||||
uses: #{scanner_url}
|
||||
env:
|
||||
|
@ -91,29 +92,7 @@ class Api::V1::SonarqubesController < Api::V1::BaseController
|
|||
sonar_scanner_content[:content] = Base64.strict_encode64(sonar_scanner_content[:content])
|
||||
Gitea::CreateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_scanner_content)
|
||||
end
|
||||
|
||||
sonar_content = build_sonar_content(params[:owner], @project.id, languages_precentagable.keys)
|
||||
|
||||
sonar_project_content = {
|
||||
filepath: 'sonar-project.properties',
|
||||
branch: params[:branch],
|
||||
new_branch: nil,
|
||||
"content": sonar_content,
|
||||
"message": 'Add sonar-project.properties',
|
||||
committer: {
|
||||
email: @owner.mail,
|
||||
name: @owner.login
|
||||
},
|
||||
identifier: @project.identifier
|
||||
}
|
||||
|
||||
sonar_project_exit = Repositories::EntriesInteractor.call(@owner, @project.identifier, 'sonar-project.properties', ref: params[:branch])
|
||||
if sonar_project_exit.success?
|
||||
Gitea::UpdateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_project_content.merge(sha:sonar_project_exit.result['sha']))
|
||||
else
|
||||
sonar_project_content[:content] = Base64.strict_encode64(sonar_project_content[:content])
|
||||
Gitea::CreateFileInteractor.call(@owner.gitea_token, @owner.login, sonar_project_content)
|
||||
end
|
||||
$gitea_hat_client.post_repos_actions_runs_by_owner_repo(@project&.owner&.login, @project&.identifier, {query: {workflow: "SonarScanner.yaml", ref: params[:branch]}})
|
||||
render_ok
|
||||
end
|
||||
|
||||
|
|
|
@ -330,20 +330,6 @@ class ApplicationController < ActionController::Base
|
|||
User.current = find_current_user
|
||||
uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous"))
|
||||
|
||||
# # 开放课程通过链接访问的用户
|
||||
# if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank?
|
||||
# content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}"
|
||||
#
|
||||
# if Digest::MD5.hexdigest(content) == params[:chinaoocKey]
|
||||
# user = open_class_user
|
||||
# if user
|
||||
# start_user_session(user)
|
||||
# set_autologin_cookie(user)
|
||||
# end
|
||||
# User.current = user
|
||||
# end
|
||||
# end
|
||||
|
||||
if !User.current.logged? && Rails.env.development?
|
||||
user = User.find 1
|
||||
User.current = user
|
||||
|
@ -366,6 +352,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
UserOnline.login(User.current.id)
|
||||
# User.current = User.find 81403
|
||||
end
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ class AttachmentsController < ApplicationController
|
|||
Rails.logger.info("request.host===#{request.host},request.referer===#{request.referer}")
|
||||
tip_exception(403, "你没有权限访问") if request.host.present? && !request.referer.to_s.include?(request.host.to_s.gsub("www.",""))
|
||||
normal_status(-1, "参数缺失") if params[:download_url].blank?
|
||||
tip_exception('不可访问') if params[:download_url].to_s.include?("chinese_dictionary.txt")
|
||||
url = base_url.starts_with?("https:") ? params[:download_url].to_s.gsub("http:", "https:") : params[:download_url].to_s
|
||||
md5_file = Digest::MD5.hexdigest(params[:download_url])
|
||||
FileUtils.mkdir_p("#{Rails.root}#{EduSetting.get("attachment_folder")}gitea/") unless Dir.exists?("#{Rails.root}#{EduSetting.get("attachment_folder")}gitea/")
|
||||
|
|
|
@ -63,6 +63,7 @@ module LoginHelper
|
|||
|
||||
user.delete_autologin_token(autologin)
|
||||
user.delete_session_token(session[:tk])
|
||||
UserOnline.logout(User.current.id)
|
||||
self.logged_user = nil
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ class MainController < ApplicationController
|
|||
skip_before_action :setup_laboratory
|
||||
|
||||
def first_stamp
|
||||
render :json => { status: 0, message: Time.now.to_i }
|
||||
render :json => { status: 0, message: Time.now.to_i, online: UserOnline.count }
|
||||
end
|
||||
|
||||
def test_404
|
||||
|
|
|
@ -107,8 +107,10 @@ class Organizations::OrganizationsController < Organizations::BaseController
|
|||
tip_exception("密码不正确") unless current_user.check_password?(password)
|
||||
ActiveRecord::Base.transaction do
|
||||
gitea_destroy = Gitea::Organization::DeleteService.call(current_user.gitea_token, @organization.login)
|
||||
if gitea_destroy[:status] == 204
|
||||
if gitea_destroy[:status] == 204
|
||||
data_bank = @organization.attributes.to_json
|
||||
@organization.destroy!
|
||||
UserAction.create(action_id: @organization.id, action_type: "DestroyOrganization", user_id: current_user.id, :ip => request.remote_ip, data_bank: data_bank)
|
||||
render_ok
|
||||
elsif gitea_destroy[:status] == 500
|
||||
tip_exception("当组织内含有仓库时,无法删除此组织")
|
||||
|
|
|
@ -383,6 +383,24 @@ class ProjectsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def clone_detection
|
||||
forge_url = "#{Rails.application.config_for(:configuration)['platform_url']}"
|
||||
target_dir = "2-#{SecureRandom.hex(6)}"
|
||||
source_url = "#{forge_url}/#{@project.owner.name}/#{@project.identifier}.git"
|
||||
source_dir = "#{@project.id}-#{SecureRandom.hex(6)}"
|
||||
clone_dir = File.join(Rails.root, "public", "clone_detection")
|
||||
system("cd #{clone_dir} && git clone #{params[:target_url]} #{target_dir}")
|
||||
system("cd #{clone_dir} && git clone #{source_url} #{source_dir}")
|
||||
system("cd /var/www/NiCad-6.2 && ./nicad6cross functions java /var/www/forgeplus/public/clone_detection/#{source_dir} /var/www/forgeplus/public/clone_detection/#{target_dir}")
|
||||
view_url = "#{forge_url}/#{source_dir}_functions-blind-crossclones/#{source_dir}_functions-blind-crossclones-0.30-classes-withsource.html"
|
||||
system("rm -rf /var/www/forgeplus/public/clone_detection/#{source_dir}")
|
||||
system("rm -rf /var/www/forgeplus/public/clone_detection/#{target_dir}")
|
||||
render_ok({ view_url: view_url })
|
||||
rescue
|
||||
Rails.logger.info("clone_detection...............error,#{forge_url},#{source_url}")
|
||||
system("rm -rf /var/www/forgeplus/public/clone_detection/#{source_dir}")
|
||||
system("rm -rf /var/www/forgeplus/public/clone_detection/#{target_dir}")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ class RepositoriesController < ApplicationController
|
|||
|
||||
def sub_entries
|
||||
file_path_uri = URI.parse(URI.encode(params[:filepath].to_s.strip))
|
||||
|
||||
tip_exception('不可访问') if params[:filepath].to_s.include?("chinese_dictionary.txt")
|
||||
if @project.educoder?
|
||||
if params[:type] === 'file'
|
||||
@sub_entries = Educoder::Repository::Entries::GetService.call(@project&.project_educoder&.repo_name, file_path_uri)
|
||||
|
@ -307,6 +307,7 @@ class RepositoriesController < ApplicationController
|
|||
def raw
|
||||
domain = GiteaService.gitea_config[:domain]
|
||||
api_url = GiteaService.gitea_config[:base_url]
|
||||
tip_exception('不可访问') if params[:filepath].to_s.include?("chinese_dictionary.txt")
|
||||
|
||||
url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{CGI.escape(params[:filepath])}?ref=#{CGI.escape(params[:ref])}"
|
||||
file_path = [domain, api_url, url].join
|
||||
|
|
|
@ -9,7 +9,7 @@ class Users::OrganizationsController < Users::BaseController
|
|||
@organizations = observed_user.organizations.with_visibility("common")
|
||||
end
|
||||
|
||||
@organizations = @organizations.ransack(login_cont: params[:search]).result if params[:search].present?
|
||||
@organizations = @organizations.ransack(login_or_nickname_cont: params[:search]).result if params[:search].present?
|
||||
|
||||
@home_top_ids = @organizations.joins(:home_top_settings).where(home_top_settings: {user_id: observed_user.id}).order("home_top_settings.created_at asc").pluck(:id)
|
||||
|
||||
|
|
|
@ -244,7 +244,9 @@ module RepositoriesHelper
|
|||
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
|
||||
content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
|
||||
# readme_render_decode64_content(content, owner, repo, ref)
|
||||
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
|
||||
text = new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
|
||||
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
|
||||
text
|
||||
end
|
||||
|
||||
def decode64_content(entry, owner, repo, ref, path=nil)
|
||||
|
@ -253,9 +255,13 @@ module RepositoriesHelper
|
|||
content = entry['content'].present? ? entry['content'] : Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
|
||||
# Rails.logger.info("content===#{content}")
|
||||
return Base64.decode64(content).force_encoding("GBK").encode("UTF-8") unless Base64.decode64(content).force_encoding('UTF-8').valid_encoding?
|
||||
return Base64.decode64(content).force_encoding('UTF-8')
|
||||
text = Base64.decode64(content).force_encoding('UTF-8')
|
||||
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
|
||||
text
|
||||
elsif entry['is_text_file'] == true
|
||||
return render_decode64_content(entry['content'])
|
||||
text = render_decode64_content(entry['content'])
|
||||
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
|
||||
text
|
||||
else
|
||||
file_type = File.extname(entry['name'].to_s)[1..-1]
|
||||
if image_type?(file_type)
|
||||
|
@ -264,7 +270,9 @@ module RepositoriesHelper
|
|||
if download_type(file_type)
|
||||
return entry['content']
|
||||
end
|
||||
render_decode64_content(entry['content'])
|
||||
text = render_decode64_content(entry['content'])
|
||||
text = "该内容不合规,请修改。" if text.present? && !HarmoniousDictionary.clean?(text)
|
||||
text
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -13,30 +13,31 @@ module SonarService
|
|||
|
||||
lines = []
|
||||
lines << "sonar.projectKey=#{owner}-#{project_id}"
|
||||
lines << "sonar.projectVersion=1.0"
|
||||
lines << "sonar.sourceEncoding=UTF-8"
|
||||
lines << "sonar.sources=."
|
||||
lines << "sonar.exclusions=**/test/**,**/tests/**,**/vendor/**,**/node_modules/**,**/__pycache__/**"
|
||||
lines << " sonar.projectVersion=1.0"
|
||||
lines << " sonar.sourceEncoding=UTF-8"
|
||||
lines << " sonar.sources=."
|
||||
lines << " sonar.exclusions=**/test/**,**/tests/**,**/vendor/**,**/node_modules/**,**/__pycache__/**"
|
||||
|
||||
if detected_langs.include?(:java)
|
||||
lines << "sonar.java.binaries="
|
||||
lines << " sonar.java.binaries=build_tmp_folder"
|
||||
lines << " sonar.language=java"
|
||||
end
|
||||
|
||||
if detected_langs.include?(:js)
|
||||
lines << "sonar.javascript.lcov.reportPaths=coverage/lcov.info"
|
||||
lines << " sonar.javascript.lcov.reportPaths=coverage/lcov.info"
|
||||
end
|
||||
|
||||
if detected_langs.include?(:ts)
|
||||
lines << "sonar.typescript.tsconfigPath=tsconfig.json"
|
||||
lines << " sonar.typescript.tsconfigPath=tsconfig.json"
|
||||
end
|
||||
|
||||
if detected_langs.include?(:python)
|
||||
lines << "sonar.python.coverage.reportPaths=coverage.xml"
|
||||
lines << " sonar.python.coverage.reportPaths=coverage.xml"
|
||||
end
|
||||
|
||||
if detected_langs.include?(:cpp)
|
||||
lines << "sonar.cxx.file.suffixes=.cpp,.c,.cc,.h,.hpp,.hh"
|
||||
lines << "sonar.cxx.errorRecoveryEnabled=true"
|
||||
lines << " sonar.cxx.file.suffixes=.cpp,.c,.cc,.h,.hpp,.hh"
|
||||
lines << " sonar.cxx.errorRecoveryEnabled=true"
|
||||
end
|
||||
|
||||
lines.join("\n")
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
module UserOnline
|
||||
class << self
|
||||
redis_config = YAML.load_file(Rails.root.join('config', 'redis.yml'))
|
||||
if redis_config.present?
|
||||
redis_url = redis_config[Rails.env]['url']
|
||||
$redis = Redis.new({:url=>redis_url})
|
||||
else
|
||||
$redis = Rails.cache.data
|
||||
end
|
||||
def login(user_id)
|
||||
set_bit(user_id, 1)
|
||||
end
|
||||
|
||||
def logout(user_id)
|
||||
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
|
||||
now = Time.now()
|
||||
keys = []
|
||||
(1..5).each do |i|
|
||||
key = (now - i.minutes).strftime("%H-%M")
|
||||
keys << "cache:online_user_#{key}"
|
||||
set_bit_and_expire(cache_key, user_id, 0) unless $redis.ttl(cache_key) == -2
|
||||
end
|
||||
end
|
||||
set_bit(user_id, 0)
|
||||
end
|
||||
|
||||
def set_bit(user_id, flag)
|
||||
if $redis.ttl(cache_key) == -2
|
||||
# 如果key不存在
|
||||
set_bit_and_expire(cache_key, user_id, flag)
|
||||
else
|
||||
if $redis.ttl(cache_key) ==-1
|
||||
# 可以存在,但过期时间没关联
|
||||
# 这种情况大概率是并发原因导致对相应key设置过期时跳过了。所以删除并重新设置过期时间
|
||||
$redis.del(cache_key)
|
||||
set_bit_and_expire(cache_key, user_id, flag)
|
||||
end
|
||||
|
||||
# 统计当前时间下,前5分钟的活跃人数
|
||||
$redis.setbit(cache_key, user_id, flag)
|
||||
end
|
||||
end
|
||||
|
||||
def set_bit_and_expire(cache_key, user_id, flag)
|
||||
$redis.setbit(cache_key, user_id, flag)
|
||||
# $redis.setbit(last_cache_key, user_id, flag)
|
||||
# 现在统计5分钟在线人数,这里设置6分钟过期,目的是统计当前时刻的前5分钟
|
||||
$redis.expire(cache_key, 6 * 60)
|
||||
end
|
||||
|
||||
def count
|
||||
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
|
||||
now = Time.now()
|
||||
keys = []
|
||||
(0..4).each do |i|
|
||||
key = (now - i.minutes).strftime("%H-%M")
|
||||
keys << "cache:online_user_#{key}"
|
||||
end
|
||||
# 防止每个分钟数据有重复,所以去重去除
|
||||
$redis.bitop("OR", "daiao", keys)
|
||||
$redis.bitcount("daiao")
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
|
||||
def cache_key
|
||||
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
|
||||
"cache:online_user_#{Time.now().strftime("%H-%M")}"
|
||||
else
|
||||
raise '请配置config.cache_store = redis_store'
|
||||
end
|
||||
end
|
||||
|
||||
def last_cache_key
|
||||
if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore)
|
||||
# 如设置5分钟内即300秒有请求的用户视为在线, 则最大会统计到10分钟内有活动用户
|
||||
# TODO 更精确时长
|
||||
begin_hour = Time.now.beginning_of_hour
|
||||
minutes_piece = (Time.now - begin_hour) / (60 * 5)
|
||||
time = begin_hour.since((minutes_piece.to_i - 1) * (60 * 5)).strftime("%H-%M")
|
||||
"cache:online_user_#{time}"
|
||||
else
|
||||
raise '请配置config.cache_store = redis_store'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -105,6 +105,23 @@ class Issue < ApplicationRecord
|
|||
scope :pm_includes, -> {includes(:project, :show_issue_tags, :issue_status, :priority, :version, :user, :show_assigners, :comment_journals, :operate_journals)}
|
||||
scope :closed, ->{where(status_id: 5)}
|
||||
scope :opened, ->{where.not(status_id: 5)}
|
||||
scope :with_assigner_info, -> {
|
||||
joins("LEFT JOIN (
|
||||
SELECT ia.issue_id, ia.assigner_id
|
||||
FROM issue_assigners ia
|
||||
JOIN (
|
||||
SELECT issue_id, MIN(id) AS min_assigner_id
|
||||
FROM issue_assigners
|
||||
GROUP BY issue_id
|
||||
) tmp ON ia.issue_id = tmp.issue_id AND ia.id = tmp.min_assigner_id
|
||||
) assigner ON issues.id = assigner.issue_id
|
||||
LEFT JOIN users u ON assigner.assigner_id = u.id")
|
||||
}
|
||||
|
||||
scope :ordered_by_assigner, -> (sort_direction) {
|
||||
order("CASE WHEN u.id IS NULL THEN 1 ELSE 0 END ASC")
|
||||
.order("COALESCE(u.nickname, u.login) #{sort_direction}")
|
||||
}
|
||||
after_create :incre_project_common, :incre_user_statistic, :incre_platform_statistic
|
||||
before_save :check_pm_and_update_due_date
|
||||
after_save :incre_or_decre_closed_issues_count, :change_versions_count, :send_update_message_to_notice_system, :associate_attachment_container, :generate_uuid
|
||||
|
@ -124,6 +141,20 @@ class Issue < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def pm_issue_type_chinese_string
|
||||
case pm_issue_type
|
||||
when 1
|
||||
"需求"
|
||||
when 2
|
||||
"任务"
|
||||
when 3
|
||||
"缺陷"
|
||||
else
|
||||
"疑修"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def destroy_be_pm_links
|
||||
PmLink.where(be_linkable_type:"Issue",be_linkable_id:self.id).map(&:destroy)
|
||||
end
|
||||
|
|
|
@ -483,36 +483,30 @@ class Journal < ApplicationRecord
|
|||
end
|
||||
return content
|
||||
when 'link_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| i.pm_issue_type.nil? && i.pm_project_id.nil? ? "疑修 <b>【#{i.subject}】</b>" : "工作项 <b>[#{i.pm_issue_type_chinese_string}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| i.pm_issue_type.nil? && i.pm_project_id.nil? ? "疑修 <b>【#{i.subject}】</b>" : "工作项 <b>[#{i.pm_issue_type_chinese_string}]-<#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "新建了关联的工作项#{new_value}"
|
||||
content += "新建了关联的#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "删除了关联的工作项#{old_value}"
|
||||
content += "删除了关联的#{old_value}"
|
||||
else
|
||||
content += "新建了关联的工作项#{new_value}"
|
||||
content += "新建了关联的#{new_value}"
|
||||
end
|
||||
end
|
||||
content.gsub!('1', "需求")
|
||||
content.gsub!('2', "任务")
|
||||
content.gsub!('3', "缺陷")
|
||||
return content
|
||||
when 'tag_link_issue'
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| "<b>[#{i.pm_issue_type}]-<#{i.subject}></b>"}.join("、")
|
||||
old_value = Issue.where(id: detail.old_value.to_s.split(",")).map{|i| i.pm_issue_type.nil? && i.pm_project_id.nil? ? "疑修 <b>【#{i.subject}】</b>" : "工作项 <b>[#{i.pm_issue_type_chinese_string}]-<#{i.subject}></b>"}.join("、")
|
||||
new_value = Issue.where(id: detail.value.to_s.split(",")).map{|i| i.pm_issue_type.nil? && i.pm_project_id.nil? ? "疑修 <b>【#{i.subject}】</b>" : "工作项 <b>[#{i.pm_issue_type_chinese_string}]-<#{i.subject}></b>"}.join("、")
|
||||
if detail.old_value.nil? || detail.old_value.blank?
|
||||
content += "关联了工作项#{new_value}"
|
||||
content += "关联了#{new_value}"
|
||||
else
|
||||
if detail.value.nil? || detail.value.blank?
|
||||
content += "取消了关联的工作项#{old_value}"
|
||||
content += "取消了关联的#{old_value}"
|
||||
else
|
||||
content += "关联了工作项#{new_value}"
|
||||
content += "关联了#{new_value}"
|
||||
end
|
||||
end
|
||||
content.gsub!('1', "需求")
|
||||
content.gsub!('2', "任务")
|
||||
content.gsub!('3', "缺陷")
|
||||
return content
|
||||
when 'issue'
|
||||
issue = self.issue
|
||||
|
@ -535,6 +529,7 @@ class Journal < ApplicationRecord
|
|||
case detail.property
|
||||
when 'issue'
|
||||
content += "创建了<b>疑修</b>"
|
||||
return content
|
||||
when 'attachment'
|
||||
old_value = Attachment.where("BINARY id in (?) or uuid in (?)", detail.old_value.to_s.split(","), detail.old_value.to_s.split(",")).pluck(:filename).join("、")
|
||||
new_value = Attachment.where("BINARY id in (?) or uuid in (?)", detail.value.to_s.split(","), detail.value.to_s.split(",")).pluck(:filename).join("、")
|
||||
|
@ -544,6 +539,7 @@ class Journal < ApplicationRecord
|
|||
new_value = "无" if new_value.blank?
|
||||
content += "将附件由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
return content
|
||||
when 'issue_tag'
|
||||
old_value = IssueTag.where(id: detail.old_value.split(",")).pluck(:name).join("、")
|
||||
new_value = IssueTag.where(id: detail.value.split(",")).pluck(:name).join("、")
|
||||
|
@ -553,6 +549,7 @@ class Journal < ApplicationRecord
|
|||
new_value = "无" if new_value.blank?
|
||||
content += "将标记由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
return content
|
||||
when 'assigner'
|
||||
old_value = User.where(id: detail.old_value.split(",")).map{|u| u.real_name}.join("、")
|
||||
new_value = User.where(id: detail.value.split(",")).map{|u| u.real_name}.join("、")
|
||||
|
@ -562,6 +559,7 @@ class Journal < ApplicationRecord
|
|||
new_value = "无" if new_value.blank?
|
||||
content += "将负责人由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
return content
|
||||
when 'attr'
|
||||
content += "将"
|
||||
case detail.prop_key
|
||||
|
@ -604,8 +602,9 @@ class Journal < ApplicationRecord
|
|||
new_value = "无" if new_value.blank?
|
||||
content += "由<b>#{old_value}</b>更改为<b>#{new_value}</b>"
|
||||
end
|
||||
return content
|
||||
end
|
||||
|
||||
content = self.pm_operate_content if content == ""
|
||||
end
|
||||
|
||||
def journal_content
|
||||
|
|
|
@ -39,7 +39,7 @@ class Laboratory < ApplicationRecord
|
|||
|
||||
validates :identifier, uniqueness: { case_sensitive: false }, allow_nil: true
|
||||
|
||||
delegate :name, :navbar, :footer, :login_logo_url, :nav_logo_url, :tab_logo_url, :default_navbar, to: :laboratory_setting
|
||||
delegate :name, :navbar, :footer, :login_logo_url, :nav_logo_url, :pm_logo_url, :tab_logo_url, :default_navbar, to: :laboratory_setting
|
||||
|
||||
def site
|
||||
rails_env = EduSetting.get('rails_env')
|
||||
|
|
|
@ -34,7 +34,9 @@ class LaboratorySetting < ApplicationRecord
|
|||
def nav_logo_url
|
||||
image_url('nav')
|
||||
end
|
||||
|
||||
def pm_logo_url
|
||||
image_url('pm_logo')
|
||||
end
|
||||
def tab_logo_url
|
||||
image_url('tab')
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ class ProjectTrend < ApplicationRecord
|
|||
CREATE = 'create'
|
||||
MERGE = 'merge'
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :project, optional: true
|
||||
belongs_to :trend, polymorphic: true, optional: true
|
||||
belongs_to :user
|
||||
end
|
||||
|
|
|
@ -144,6 +144,18 @@ class PullRequest < ApplicationRecord
|
|||
"#{Rails.application.config_for(:configuration)['platform_url']}/#{self.project.owner.login}/#{self.project.name}/pulls/#{self.id}"
|
||||
end
|
||||
|
||||
def closed?
|
||||
self.status == CLOSED
|
||||
end
|
||||
|
||||
def merged?
|
||||
self.status == MERGED
|
||||
end
|
||||
|
||||
def opened?
|
||||
self.status == OPEN
|
||||
end
|
||||
|
||||
def pr_status
|
||||
case status
|
||||
when 0
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
# == Schema Information
|
||||
#
|
||||
# Table name: tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer default("0"), not null
|
||||
# action :string(30) default(""), not null
|
||||
# value :string(40) default(""), not null
|
||||
# created_on :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_tokens_on_user_id (user_id)
|
||||
# tokens_value (value) UNIQUE
|
||||
#
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: tokens
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# user_id :integer default("0"), not null
|
||||
# action :string(30) default(""), not null
|
||||
# value :string(40) default(""), not null
|
||||
# created_on :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_tokens_on_user_id (user_id)
|
||||
# tokens_value (value) UNIQUE
|
||||
#
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
@ -50,7 +50,10 @@ class Token < ActiveRecord::Base
|
|||
token = Token.create(:user => user, :action => type)
|
||||
Rails.logger.info "###### Token.get_token_from_user is nul and agine create token: #{token&.value}"
|
||||
else
|
||||
token.update_attribute(:created_on, Time.now)
|
||||
unless Rails.cache.read("token::update::created_on::#{token.id}").present?
|
||||
token.update_attribute(:created_on, Time.now)
|
||||
Rails.cache.write("token::update::created_on::#{token.id}", true, expires_in: 5.minutes)
|
||||
end
|
||||
end
|
||||
token
|
||||
end
|
||||
|
|
|
@ -693,8 +693,9 @@ class User < Owner
|
|||
def self.try_to_autologin(key)
|
||||
user = Token.find_active_user('autologin', key)
|
||||
if user
|
||||
Rails.cache.fetch("user::update::last_login_on::#{user.id}",:expires_in => 5.minutes) do
|
||||
unless Rails.cache.read("user::update::last_login_on::#{user.id}").present?
|
||||
user.update(last_login_on: Time.now)
|
||||
Rails.cache.write("user::update::last_login_on::#{user.id}", true, expires_in: 5.minutes)
|
||||
end
|
||||
end
|
||||
user
|
||||
|
|
|
@ -31,10 +31,11 @@ class UserAction < ApplicationRecord
|
|||
|
||||
def action_name
|
||||
case action_type
|
||||
when "DestroyUser" then "用户注销"
|
||||
when "DestroyUser" then "删除用户"
|
||||
when "DestroyProject" then "删除项目"
|
||||
when "Login" then "登录"
|
||||
when "Logout" then "退出登录"
|
||||
when "DestroyOrganization" then "删除组织"
|
||||
else self.action_type
|
||||
end
|
||||
end
|
||||
|
@ -53,6 +54,7 @@ class UserAction < ApplicationRecord
|
|||
case action_type
|
||||
when "DestroyUser" then "账号:#{user&.login}<br/>邮箱:#{user&.mail}<br/>手机号:#{user&.phone}<br/>昵称:#{user&.nickname}<br/>"
|
||||
when "DestroyProject" then "项目名称:#{project&.name}<br/>项目标识:#{project&.identifier}<br/>"
|
||||
when "DestroyOrganization" then "组织名称:#{organization&.nickname}<br/>组织标识:#{organization&.login}<br/>"
|
||||
else "--"
|
||||
end
|
||||
end
|
||||
|
@ -74,6 +76,17 @@ class UserAction < ApplicationRecord
|
|||
end
|
||||
action_project
|
||||
end
|
||||
|
||||
def organization
|
||||
action_organization = if action_type == "DestroyOrganization" && data_bank.present?
|
||||
build_mode("Organization")
|
||||
else
|
||||
Organization.find_by(id: self.action_id)
|
||||
end
|
||||
action_organization
|
||||
end
|
||||
|
||||
|
||||
def build_mode(model_name)
|
||||
model = model_name.constantize.new
|
||||
model_name.constantize.column_names.each do |col|
|
||||
|
|
|
@ -40,6 +40,7 @@ class Admins::SaveLaboratorySettingService < ApplicationService
|
|||
save_image_file(params[:nav_logo], 'nav')
|
||||
save_image_file(params[:login_logo], 'login')
|
||||
save_image_file(params[:tab_logo], 'tab')
|
||||
save_image_file(params[:pm_logo], 'pm_logo')
|
||||
save_image_file(params[:subject_banner], '_subject_banner')
|
||||
save_image_file(params[:course_banner], '_course_banner')
|
||||
save_image_file(params[:competition_banner], '_competition_banner')
|
||||
|
|
|
@ -9,7 +9,7 @@ class Api::V1::Issues::ListService < ApplicationService
|
|||
|
||||
validates :category, inclusion: { in: %w[all opened closed], message: '请输入正确的Category'}
|
||||
validates :participant_category, inclusion: { in: %w[all aboutme authoredme assignedme atme], message: '请输入正确的ParticipantCategory'}
|
||||
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_by, inclusion: { in: %w[issues.created_on issues.updated_on issues.blockchain_token_num issue_priorities.position issues.start_date issues.due_date issues.status_id, assigners] , message: '请输入正确的SortBy'}, allow_blank: true
|
||||
validates :sort_direction, inclusion: { in: %w[asc desc], message: '请输入正确的SortDirection'}, allow_blank: true
|
||||
validates :current_user, presence: true
|
||||
|
||||
|
@ -175,6 +175,8 @@ class Api::V1::Issues::ListService < ApplicationService
|
|||
scope = issues.includes(:priority, :issue_status, :user, :show_assigners, :show_issue_tags, :version, :comment_journals)
|
||||
scope = if sort_by == 'issue_priorities.position'
|
||||
scope.reorder("issue_priorities.position #{sort_direction}, issues.updated_on DESC").distinct
|
||||
elsif sort_by == 'assigners'
|
||||
scope.with_assigner_info.ordered_by_assigner(sort_direction)
|
||||
else
|
||||
scope.reorder("#{sort_by} #{sort_direction}").distinct
|
||||
end
|
||||
|
|
|
@ -25,7 +25,9 @@ class Api::V1::Projects::Commits::RecentService < ApplicationService
|
|||
param = {
|
||||
access_token: token,
|
||||
page: page,
|
||||
limit: limit
|
||||
limit: limit,
|
||||
stats: false,
|
||||
files: false
|
||||
}
|
||||
param.merge!(keyword: keyword) if keyword.present?
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
class Api::V1::Projects::Pulls::ReopenService < ApplicationService
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_reader :project, :pull_request, :issue, :user
|
||||
|
||||
|
||||
def initialize(project, pull_request, user)
|
||||
@project = project
|
||||
@pull_request = pull_request
|
||||
@issue = pull_request&.issue
|
||||
@user = user
|
||||
end
|
||||
|
||||
def call
|
||||
raise Error, "参数错误" unless valid?
|
||||
if gitea_change_status
|
||||
@pull_request.update_column(:status, PullRequest::OPEN)
|
||||
@pull_request&.project_trends&.where(action_type: ProjectTrend::CLOSE).destroy_all
|
||||
@issue.update_column(:status_id, IssueStatus::ADD)
|
||||
|
||||
return true
|
||||
else
|
||||
raise Error, 'gitea change status failed'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def valid?
|
||||
return false if @project.blank? || @pull_request.blank? || @issue.blank? || @user.blank?
|
||||
return false unless @pull_request.closed?
|
||||
return true
|
||||
end
|
||||
|
||||
def gitea_change_status
|
||||
gitea_result = Gitea::PullRequest::ChangeStatusService.call(@project.owner.login, @project.identifier, @pull_request.gitea_number, false, @user&.gitea_token)
|
||||
return true if gitea_result[:status] == :success
|
||||
return false
|
||||
end
|
||||
end
|
|
@ -56,8 +56,18 @@ module Baidu
|
|||
return [] unless access_token.present? && start_date.present?
|
||||
source_from_data = api("source/all/a", start_date, start_date, "pv_count,visitor_count,ip_count")
|
||||
source_from = []
|
||||
#当日的bing来源数量
|
||||
bing_number = bing_link_number(start_date)
|
||||
source_from_data['items'][1].each_with_index do |source, index|
|
||||
source_from.push(((source[0].to_f / source_from_data['sum'][0][0].to_f) * 100).round(2))
|
||||
source_number = case index
|
||||
when 1 # link 数据
|
||||
source[0].to_f - bing_number
|
||||
when 2 # search数据
|
||||
source[0].to_f + bing_number
|
||||
else
|
||||
source[0].to_f
|
||||
end
|
||||
source_from.push((( source_number / source_from_data['sum'][0][0].to_f) * 100).round(2))
|
||||
end
|
||||
daily_statistic = DailyPlatformStatistic.find_or_initialize_by(date: start_date)
|
||||
daily_statistic.source_through = source_from[0]
|
||||
|
@ -67,6 +77,30 @@ module Baidu
|
|||
daily_statistic.save
|
||||
end
|
||||
|
||||
def bing_link_number(start_date)
|
||||
return [] unless access_token.present? && start_date.present?
|
||||
source_from_data = api("source/link/a", start_date, start_date, "pv_count")
|
||||
# 提取链接项和对应的数据项
|
||||
link_items = source_from_data["items"][0]
|
||||
value_items = source_from_data["items"][1]
|
||||
|
||||
# 目标链接名称
|
||||
target_name = "http://cn.bing.com"
|
||||
target_number = 0
|
||||
|
||||
# 遍历查找匹配的 name
|
||||
link_items.each_with_index do |link_array, index|
|
||||
link = link_array.first
|
||||
if link["name"] == target_name
|
||||
stats = value_items[index]
|
||||
target_number = stats[0]
|
||||
break
|
||||
end
|
||||
end
|
||||
target_number.to_f
|
||||
end
|
||||
|
||||
|
||||
def diff_days(start_date, end_date)
|
||||
(end_date.beginning_of_day.to_i - start_date.beginning_of_day.to_i) / (24 * 3600)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# Get a pull request
|
||||
class Gitea::PullRequest::ChangeStatusService < Gitea::ClientService
|
||||
attr_reader :owner, :repo, :number, :is_closed, :token
|
||||
|
||||
#eq:
|
||||
# Gitea::PullRequest::ChangeStatusService.call(user.login, repository.identifier, pull.gitea_number, true, user.gitea_token)
|
||||
def initialize(owner, repo, number, is_closed, token=nil)
|
||||
@owner = owner
|
||||
@repo = repo
|
||||
@number = number
|
||||
@is_closed = is_closed
|
||||
@token = token
|
||||
end
|
||||
|
||||
def call
|
||||
response = get(url, request_params, true)
|
||||
status, message, body = render_response(response)
|
||||
json_format(status, message, body)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request_params
|
||||
Hash.new.merge(token: token, is_closed: is_closed)
|
||||
end
|
||||
|
||||
def url
|
||||
"/repos/#{owner}/#{repo}/pulls/#{number}/change_status".freeze
|
||||
end
|
||||
|
||||
def json_format(status, message, body)
|
||||
case status
|
||||
when 204 then success(body)
|
||||
else
|
||||
error(message, status)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
<% add_admin_breadcrumb('概览', admins_path) %>
|
||||
<% end %>
|
||||
|
||||
<% cache "/admin/dashboards/#{Time.now.strftime('%Y-%m-%d')}", :expires_in => 1.days do %>
|
||||
<%# cache_if EduSetting.get("open_baidu_tongji").to_s == "true", "/admin/dashboards/#{Time.now.strftime('%Y-%m-%d')}", :expires_in => 1.days do %>
|
||||
<div class="header bg-gradient-primary pb-8 pt-md-8">
|
||||
<div class="container-fluid">
|
||||
<div class="header-body">
|
||||
|
@ -32,7 +32,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%end %>
|
||||
<%#end %>
|
||||
|
||||
<div class="box admin-list-container project-language-list-container">
|
||||
<table class="table table-hover text-center subject-list-table">
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<div class="setting-item-head"><h6>Logo设置</h6></div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<div class="pl-0 py-3 row setting-item-body">
|
||||
<div class="col-12 col-md-4 logo-item">
|
||||
<div class="col-12 col-md-3 logo-item">
|
||||
<% nav_logo_img = setting.nav_logo_url %>
|
||||
<div class="logo-item-left mr-3 <%= nav_logo_img ? 'has-img' : '' %>">
|
||||
<img class="logo-item-img nav-logo-img" src="<%= nav_logo_img %>" style="<%= nav_logo_img.present? ? '' : 'display: none' %>"/>
|
||||
|
@ -56,7 +56,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4 logo-item">
|
||||
<div class="col-12 col-md-3 logo-item">
|
||||
<% login_logo_img = setting.login_logo_url %>
|
||||
<div class="logo-item-left mr-3 <%= login_logo_img ? 'has-img' : '' %>">
|
||||
<img class="logo-item-img login-logo-img" src="<%= login_logo_img %>" style="<%= login_logo_img.present? ? '' : 'display: none' %>"/>
|
||||
|
@ -70,7 +70,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-4 logo-item">
|
||||
<div class="col-12 col-md-3 logo-item">
|
||||
<% tab_logo_img = setting.tab_logo_url %>
|
||||
<div class="logo-item-left mr-3 <%= tab_logo_img ? 'has-img' : '' %>">
|
||||
<img class="logo-item-img tab-logo-img" src="<%= tab_logo_img %>" style="<%= tab_logo_img.present? ? '' : 'display: none' %>"/>
|
||||
|
@ -83,6 +83,21 @@
|
|||
<div>尺寸:16*16 32*32 48*48 64*64 </div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-md-3 logo-item">
|
||||
<% pm_logo_img = setting.pm_logo_url %>
|
||||
<div class="logo-item-left mr-3 <%= pm_logo_img ? 'has-img' : '' %>">
|
||||
<img class="logo-item-img tab-logo-img" src="<%= pm_logo_img %>" style="<%= tab_logo_img.present? ? '' : 'display: none' %>"/>
|
||||
<%= file_field_tag(:pm_logo, accept: 'image/png,image/jpg,image/jpeg', style: 'display: none', value: params[:pm_logo]) %>
|
||||
<label for="pm_logo" class="logo-item-upload" data-toggle="tooltip" data-title="选择图片"></label>
|
||||
</div>
|
||||
<div class="logo-item-right">
|
||||
<div class="logo-item-title flex-1">PM管理端logo</div>
|
||||
<div>格式:PNG、JPG</div>
|
||||
<div>尺寸:高度90px以内,宽等比例缩放</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
<td><%= link_to org.organization_users_count, "/#{org.login}", target: "_blank" %></td>
|
||||
<td><%= link_to org.projects_count, "/#{org.login}", target: "_blank" %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<%= javascript_void_link '开通CLA', class: 'action open-cla-action', data: { id: org.id }, style: org.open_cla? ? 'display: none;' : '' %>
|
||||
<%= javascript_void_link '关闭CLA', class: 'action close-cla-action', data: { id: org.id }, style: org.open_cla? ? '' : 'display: none;' %>
|
||||
<%= link_to '查看', admins_organization_path(org), class: 'action' %>
|
||||
|
@ -36,6 +37,7 @@
|
|||
<%= delete_link '删除', admins_organization_path(org, element: ".user-item-#{org.id}"), class: 'dropdown-item delete-user-action' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -25,8 +25,10 @@
|
|||
<td><%= project_category.projects.select(:id).where(is_pinned: true).size %></td>
|
||||
<td><%= project_category.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "编辑", edit_admins_project_category_path(project_category), remote: true, class: "action" %>
|
||||
<%= link_to "删除", admins_project_category_path(project_category), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
|
||||
<% end %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "新增", new_admins_project_category_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
|
||||
<% end%>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container project-category-list-container">
|
||||
|
|
|
@ -31,8 +31,10 @@
|
|||
=end%>
|
||||
<td><%= project_ignore.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "编辑", edit_admins_project_ignore_path(project_ignore),remote: true, class: "action" %>
|
||||
<%= link_to "删除", admins_project_ignore_path(project_ignore), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -8,7 +8,10 @@
|
|||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
|
||||
<% end %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "新增", new_admins_project_ignore_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container project-ignore-list-container">
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
<td><%= project_language.projects_count %></td>
|
||||
<td><%= project_language.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "编辑", edit_admins_project_language_path(project_language), remote: true, class: "action" %>
|
||||
<%= link_to "删除", admins_project_language_path(project_language), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
|
||||
<% end %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "新增", new_admins_project_language_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
|
||||
<% end%>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container project-language-list-container">
|
||||
|
|
|
@ -33,8 +33,10 @@
|
|||
=end%>
|
||||
<td><%= project_license.created_at&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "编辑", edit_admins_project_license_path(project_license),remote: true, class: "action" %>
|
||||
<%= link_to "删除", admins_project_license_path(project_license), method: :delete, data:{confirm: "确认删除的吗?"}, class: "action" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<input type="reset" class="btn btn-secondary clear-btn" value="清空"/>
|
||||
<% end %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to "新增", new_admins_project_license_path, remote: true, class: "btn btn-primary pull-right", "data-disabled-with":"...新增" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container project-license-list-container">
|
||||
|
|
|
@ -37,12 +37,14 @@
|
|||
</td>
|
||||
<td><%= project.created_on&.strftime('%Y-%m-%d %H:%M') %></td>
|
||||
<td class="action-container">
|
||||
<% if current_user.admin? %>
|
||||
<% if project.is_public %>
|
||||
<%= javascript_void_link '推荐', class: 'action recommend-action', data: { id: project.id }, style: project.recommend ? 'display: none;' : '' %>
|
||||
<%= javascript_void_link '取消推荐', class: 'action unrecommend-action', data: { id: project.id }, style: project.recommend ? '' : 'display: none;' %>
|
||||
<%= link_to "设置推荐等级", edit_admins_project_path(project.id), remote: true, class: "action edit-recommend-action", style: project.recommend ? '' : 'display: none;' %>
|
||||
<% end %>
|
||||
<%= link_to "删除", admins_project_path(project.id), method: :delete, data:{confirm: "确认删除的吗?"}, class: "delete-project-action" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<li><%= sidebar_item(admins_faqs_path, 'FAQ', icon: 'question-circle', controller: 'admins-faqs', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_nps_path, 'NPS用户调研', icon: 'question-circle', controller: 'admins-nps', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_feedbacks_path, '用户反馈', icon: 'question-circle', controller: 'admins-feedbacks', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_user_actions_path, '操作记录', icon: 'pencil-square', controller: 'admins-user_actions', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_user_actions_path, '操作日志', icon: 'pencil-square', controller: 'admins-user_actions', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_system_notifications_path, '系统公告配置', icon: 'bell', controller: 'admins-system_notifications', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<% sidebar_collapse = request.cookies['admin_sidebar_collapse'].to_s == 'true' %>
|
||||
<nav id="sidebar" class="<%= sidebar_collapse ? 'active' : '' %>" data-current-controller="<%= admin_sidebar_controller %>">
|
||||
<div class="sidebar-header">
|
||||
<a href="/" class="sidebar-header-logo" data-toggle="tooltip" data-title="返回主站" >
|
||||
<!-- <img class="rounded-circle" src="/images/<%#= url_to_avatar(current_user) %>" />-->
|
||||
<span class="logo-label">后台管理</span>
|
||||
</a>
|
||||
<div id="sidebarCollapse" class="navbar-btn <%= sidebar_collapse ? 'active' : '' %>">
|
||||
<i class="fa fa-chevron-left fold" data-toggle="tooltip" data-placement="right" data-boundary="window" title="收起"></i>
|
||||
<i class="fa fa-bars unfold" data-toggle="tooltip" data-placement="right" data-boundary="window" title="展开"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Links -->
|
||||
<ul class="list-unstyled components">
|
||||
<li><%= sidebar_item(admins_path, '数据概览', icon: 'dashboard', controller: 'admins-dashboards', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li>
|
||||
<%= sidebar_item_group('#user-submenu', '用户', icon: 'user', has_permission: current_user.admin? || current_user.business?) do %>
|
||||
<li><%= sidebar_item(admins_users_path, '用户列表', icon: 'user', controller: 'admins-users', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_organizations_path, '组织列表', icon: 'user', controller: 'admins-organizations', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
<%= sidebar_item_group('#setting-submenu', '用户支持', icon: 'cogs', has_permission: current_user.admin?) do %>
|
||||
<li><%= sidebar_item(admins_faqs_path, 'FAQ', icon: 'question-circle', controller: 'admins-faqs', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_nps_path, 'NPS用户调研', icon: 'question-circle', controller: 'admins-nps', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_feedbacks_path, '用户反馈', icon: 'question-circle', controller: 'admins-feedbacks', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_user_actions_path, '操作记录', icon: 'pencil-square', controller: 'admins-user_actions', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_system_notifications_path, '系统公告配置', icon: 'bell', controller: 'admins-system_notifications', has_permission: current_user.admin?) %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
<li><%= sidebar_item(admins_laboratories_path, '导航栏配置', icon: 'cloud', controller: 'admins-laboratories', has_permission: current_user.admin?) %></li>
|
||||
<li>
|
||||
<%= sidebar_item_group('#setting-system', '开发者配置', icon: 'wrench', has_permission: current_user.admin?) do %>
|
||||
<li><%= sidebar_item(admins_sites_path, 'setting接口配置', icon: 'deaf', controller: 'admins-sites', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_edu_settings_path, '全局变量配置', icon: 'pencil-square', controller: 'admins-edu_settings', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_message_templates_path, '消息模版配置', icon: 'folder', controller: 'admins-message_templates', has_permission: current_user.admin?) %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
<li><%= sidebar_item(admins_reversed_keywords_path, '禁用词管理', icon: 'key', controller: 'admins-reversed_keywords', has_permission: current_user.admin?) %></li>
|
||||
<li>
|
||||
<%= sidebar_item_group('#projects-submenu', '开源项目', icon: 'database', has_permission: current_user.admin? || current_user.business?) do %>
|
||||
<li><%= sidebar_item(admins_projects_path, '项目列表', icon: 'database', controller: 'admins-projects', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_project_languages_path, '项目语言', icon: 'language', controller: 'admins-project_languages', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_project_categories_path, '分类列表', icon: 'sitemap', controller: 'admins-project_categories', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_project_licenses_path, '开源许可证', icon: 'file-text-o', controller: 'admins-project_licenses', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<li><%= sidebar_item(admins_project_ignores_path, '忽略文件', icon: 'git', controller: 'admins-project_ignores', has_permission: current_user.admin? || current_user.business?) %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<%= sidebar_item_group('#rank-submenu', '活跃度排行', icon: 'calendar', has_permission: current_user.admin?) do %>
|
||||
<li><%= sidebar_item(admins_users_rank_index_path, '用户活跃度排行', icon: 'user', controller: 'admins-users_rank', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_projects_rank_index_path, '项目活跃度排行', icon: 'database', controller: 'admins-projects_rank', has_permission: current_user.admin?) %></li>
|
||||
<li><%= sidebar_item(admins_issues_rank_index_path, '疑修活跃度排行', icon: 'calendar', controller: 'admins-issues_rank', has_permission: current_user.admin?) %></li>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
|
||||
<li><%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root', has_permission: current_user.admin?) %></li>
|
||||
</ul>
|
||||
</nav>
|
|
@ -5,7 +5,7 @@
|
|||
<div class="box search-form-container user-list-form">
|
||||
<%= form_tag(admins_user_actions_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %>
|
||||
操作类型:
|
||||
<% action_type_options = [['自定义',''],['用户注销','DestroyUser'], ['删除项目', 'DestroyProject']] %>
|
||||
<% action_type_options = [['自定义',''],['删除用户','DestroyUser'], ['删除项目', 'DestroyProject'], ['删除组织', 'DestroyOrganization']] %>
|
||||
<%= select_tag(:action_type_select, options_for_select(action_type_options), class: 'form-control') %>
|
||||
<%= text_field_tag(:action_type, params[:action_type], class: 'form-control col-sm-2 ml-3',style: 'display:;', placeholder: '自定义操作类型检索') %>
|
||||
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '操作人用户名/邮箱/手机号检索') %>
|
||||
|
|
|
@ -27,11 +27,11 @@
|
|||
|
||||
<%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
|
||||
<% end %>
|
||||
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to '下载导入模板', "/导入用户模板.xlsx", class: 'btn btn-secondary mr-3' %>
|
||||
|
||||
<%= javascript_void_link '导入用户', class: 'btn btn-secondary', data: { toggle: 'modal', target: '.admin-import-user-modal'} %>
|
||||
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="box admin-list-container users-list-container">
|
||||
|
|
|
@ -27,26 +27,28 @@
|
|||
<td><%= display_text(user.last_login_on&.strftime('%Y-%m-%d %H:%M')) %></td>
|
||||
<td><%= link_to user.projects_count, "/#{user.login}/projects", target: "_blank" %></td>
|
||||
<td class="action-container">
|
||||
<%= link_to '编辑', edit_admins_user_path(user), class: 'action' %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to '编辑', edit_admins_user_path(user), class: 'action' %>
|
||||
|
||||
<%= javascript_void_link '解锁', class: 'action unlock-action', data: { id: user.id }, style: user.locked? ? '' : 'display: none;' %>
|
||||
<%= javascript_void_link '解锁', class: 'action unlock-action', data: { id: user.id }, style: user.locked? ? '' : 'display: none;' %>
|
||||
|
||||
<% if user.registered? %>
|
||||
<%= javascript_void_link '激活', class: 'action active-action', data: { id: user.id } %>
|
||||
<% end %>
|
||||
<% if user.registered? %>
|
||||
<%= javascript_void_link '激活', class: 'action active-action', data: { id: user.id } %>
|
||||
<% end %>
|
||||
|
||||
<% if user.id != current_user.id %>
|
||||
<%= javascript_void_link '加锁', class: 'action lock-action', data: { id: user.id }, style: user.locked? || user.registered? ? 'display: none;' : '' %>
|
||||
<% end %>
|
||||
<% if user.id != current_user.id %>
|
||||
<%= javascript_void_link '加锁', class: 'action lock-action', data: { id: user.id }, style: user.locked? || user.registered? ? 'display: none;' : '' %>
|
||||
<% end %>
|
||||
|
||||
<div class="d-inline">
|
||||
<%= javascript_void_link('更多', class: 'action dropdown-toggle', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false) %>
|
||||
<div class="dropdown-menu more-action-dropdown">
|
||||
<%= javascript_void_link '恢复禁密账号', class: 'dropdown-item reset-login-times-action', data: { id: user.id } %>
|
||||
<%= javascript_void_link '重置Gitea Token', class: 'dropdown-item fresh-gitea-token-action', data: { id: user.id } %>
|
||||
<%= delete_link '删除', admins_user_path(user, element: ".user-item-#{user.id}"), class: 'dropdown-item delete-user-action' %>
|
||||
<div class="d-inline">
|
||||
<%= javascript_void_link('更多', class: 'action dropdown-toggle', 'data-toggle': 'dropdown', 'aria-haspopup': true, 'aria-expanded': false) %>
|
||||
<div class="dropdown-menu more-action-dropdown">
|
||||
<%= javascript_void_link '恢复禁密账号', class: 'dropdown-item reset-login-times-action', data: { id: user.id } %>
|
||||
<%= javascript_void_link '重置Gitea Token', class: 'dropdown-item fresh-gitea-token-action', data: { id: user.id } %>
|
||||
<%= delete_link '删除', admins_user_path(user, element: ".user-item-#{user.id}"), class: 'dropdown-item delete-user-action' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
json.(issue, :id, :subject, :project_issues_index)
|
||||
json.blockchain_token_num (Site.has_blockchain? && issue.project&.use_blockchain) ? issue.blockchain_token_num : nil
|
||||
json.created_at issue.created_on.strftime("%Y-%m-%d %H:%M")
|
||||
json.updated_at issue.updated_on.strftime("%Y-%m-%d %H:%M")
|
||||
json.tags issue.show_issue_tags.each do |tag|
|
||||
json.partial! "api/v1/issues/issue_tags/simple_detail", locals: {tag: tag}
|
||||
end
|
||||
json.status_name issue.issue_status&.name
|
||||
json.status_id issue.status_id
|
||||
json.status do
|
||||
if issue.issue_status.present?
|
||||
json.partial! "api/v1/issues/statues/simple_detail", locals: {status: issue.issue_status}
|
||||
else
|
||||
json.nil!
|
||||
end
|
||||
end
|
||||
json.priority_name issue.priority&.name
|
||||
json.priority_id issue.priority_id
|
||||
json.priority do
|
||||
if issue.priority.present?
|
||||
json.partial! "api/v1/issues/issue_priorities/simple_detail", locals: {priority: issue.priority}
|
||||
else
|
||||
json.nil!
|
||||
end
|
||||
end
|
||||
json.milestone_name issue.version&.name
|
||||
json.milestone_id issue.fixed_version_id
|
||||
json.root_id issue.root_id
|
||||
json.pm_issue_type issue.pm_issue_type
|
||||
json.pm_sprint_id issue.pm_sprint_id
|
||||
json.pm_project_id issue.pm_project_id
|
||||
json.time_scale issue.time_scale
|
||||
if weekly_begin_date.present? && weekly_end_date.present?
|
||||
if params[:pm_issue_types].present?
|
||||
json.child_count issue.children_issues.where(pm_issue_type: 4).where("due_date >=? and start_date <=?", weekly_begin_date, weekly_end_date).count
|
||||
else
|
||||
json.child_count issue.children_issues.where("due_date >=? and start_date <=?", weekly_begin_date, weekly_end_date).count
|
||||
end
|
||||
else
|
||||
if params[:pm_issue_types].present?
|
||||
json.child_count issue.children_issues.where(pm_issue_type: 4).count
|
||||
else
|
||||
json.child_count issue.child_count
|
||||
end
|
||||
end
|
||||
|
||||
json.author do
|
||||
json.partial! "api/v1/users/simple_user", locals: {user: issue.user}
|
||||
end
|
||||
json.assigners issue.show_assigners.each do |assigner|
|
||||
json.partial! "api/v1/users/simple_user", locals: {user: assigner}
|
||||
end
|
||||
json.comment_journals_count issue.comment_journals.size
|
||||
json.start_date issue.start_date
|
||||
json.due_date issue.due_date
|
|
@ -1,8 +1,8 @@
|
|||
json.this_week_all_issues @this_week_all_issues.each do |issue|
|
||||
json.partial! "api/v1/issues/simple_detail", locals: {issue: issue}
|
||||
json.partial! "api/pm/weekly_issues/simple_detail", locals: {issue: issue, weekly_begin_date: @weekly_begin_date, weekly_end_date: @weekly_end_date}
|
||||
end
|
||||
json.this_week_total_count @this_week_all_issues.total_count
|
||||
json.next_week_all_issues @next_week_all_issues.each do |issue|
|
||||
json.partial! "api/v1/issues/simple_detail", locals: {issue: issue}
|
||||
json.partial! "api/pm/weekly_issues/simple_detail", locals: {issue: issue, weekly_begin_date: @weekly_begin_date.to_date+1.week, weekly_end_date: @weekly_end_date.to_date+1.week}
|
||||
end
|
||||
json.next_week_total_count @next_week_all_issues.total_count
|
|
@ -1,4 +1,11 @@
|
|||
json.(issue, :id, :subject, :project_issues_index)
|
||||
json.(issue, :id, :subject, :project_issues_index, :project_id)
|
||||
json.project do
|
||||
if issue.project.present?
|
||||
json.partial! "api/v1/projects/simple_detail", locals: {project: issue.project}
|
||||
else
|
||||
json.nil!
|
||||
end
|
||||
end
|
||||
json.blockchain_token_num (Site.has_blockchain? && issue.project&.use_blockchain) ? issue.blockchain_token_num : nil
|
||||
json.created_at issue.created_on.strftime("%Y-%m-%d %H:%M")
|
||||
json.updated_at issue.updated_on.strftime("%Y-%m-%d %H:%M")
|
||||
|
@ -35,7 +42,6 @@ if params[:pm_issue_types].present?
|
|||
else
|
||||
json.child_count issue.child_count
|
||||
end
|
||||
|
||||
json.author do
|
||||
json.partial! "api/v1/users/simple_user", locals: {user: issue.user}
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ end
|
|||
if journal.is_journal_detail?
|
||||
detail = journal.journal_details.take
|
||||
json.operate_category @issue.pm_issue_type.nil? ? detail.property == "attr" ? detail.prop_key : detail.property : journal.pm_operate_category
|
||||
json.operate_content journal.is_journal_detail? ? @issue.pm_issue_type.nil? ? journal.operate_content : journal.pm_operate_content : nil
|
||||
json.operate_content journal.is_journal_detail? ? @issue.pm_project_id.nil? && @issue.pm_issue_type.nil? ? journal.operate_content : journal.pm_operate_content : nil
|
||||
else
|
||||
json.notes journal.notes
|
||||
json.comments_count journal.comments_count
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
json.total_count @projects.total_count
|
||||
json.projects @projects.each do |project|
|
||||
json.(project, :id, :name, :identifier, :description, :forked_count, :praises_count, :forked_from_project_id, :is_public)
|
||||
json.mirror_url project.repository&.mirror_url
|
||||
json.type project.numerical_for_project_type
|
||||
json.praised project.praised_by?(current_user)
|
||||
json.last_update_time render_unix_time(project.updated_on)
|
||||
json.full_last_update_time project.updated_on
|
||||
json.time_ago time_from_now(project.updated_on)
|
||||
json.language do
|
||||
if project.project_language.blank?
|
||||
json.nil!
|
||||
else
|
||||
json.id project.project_language.id
|
||||
json.name project.project_language.name
|
||||
end
|
||||
end
|
||||
json.category do
|
||||
if project.project_category.blank?
|
||||
json.nil!
|
||||
else
|
||||
json.id project.project_category.id
|
||||
json.name project.project_category.name
|
||||
end
|
||||
end
|
||||
json.topics project.project_topics.each do |topic|
|
||||
json.(topic, :id, :name)
|
||||
end
|
||||
json.url project.full_url
|
||||
json.owner do
|
||||
json.partial! "api/v1/users/simple_user", locals: {user: @organization.team_users.joins(:team).where(teams: {authorize: "owner"}).take&.user}
|
||||
end
|
||||
json.team_users_count @organization.team_users.size
|
||||
end
|
|
@ -31,7 +31,7 @@ json.author do
|
|||
json.name user.try(:show_real_name)
|
||||
json.type user&.type
|
||||
json.login user.login
|
||||
json.image_url url_to_avatar(user)
|
||||
json.image_url url_to_avatar(user).present? ? url_to_avatar(user) : User::Avatar.get_letter_avatar_url(user.login)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ json.commits_count @gitea_pull["commit_num"]
|
|||
json.files_count @gitea_pull["changed_files"]
|
||||
json.comments_count @issue.journals.parent_journals.size
|
||||
json.comments_total_count @issue.get_journals_size
|
||||
json.can_reopen @pull_request.closed?
|
||||
json.assign_user do
|
||||
json.partial! 'users/user_simple', user: @issue_assign_to
|
||||
end
|
||||
|
|
|
@ -2,6 +2,7 @@ json.setting do
|
|||
json.name default_setting.name
|
||||
json.nav_logo_url default_setting.nav_logo_url&.[](1..-1)
|
||||
json.login_logo_url default_setting.login_logo_url&.[](1..-1)
|
||||
json.pm_logo_url default_setting.pm_logo_url&.[](1..-1)
|
||||
json.tab_logo_url default_setting.tab_logo_url.present? ? default_setting.tab_logo_url&.[](1..-1) : "favicon.ico"
|
||||
json.site_page_deploy_domain @deploy_domain
|
||||
|
||||
|
|
|
@ -1,32 +1,4 @@
|
|||
习近平
|
||||
习仲勋
|
||||
贺国强
|
||||
贺子珍
|
||||
周永康
|
||||
李德生
|
||||
王岐山
|
||||
姚依林
|
||||
回良玉
|
||||
李源潮
|
||||
李干成
|
||||
戴秉国
|
||||
刘延东
|
||||
刘瑞龙
|
||||
俞正声
|
||||
薄熙来
|
||||
薄一波
|
||||
周小川
|
||||
周建南
|
||||
温云松
|
||||
江绵康
|
||||
李小鹏
|
||||
李小琳
|
||||
朱云来
|
||||
让国人愤怒的第二代身份证
|
||||
文化大革命
|
||||
胡海峰
|
||||
陈良宇
|
||||
老丁
|
||||
莱仕德事件
|
||||
fuck
|
||||
地下的先烈们纷纷打来电话询问
|
||||
|
@ -44,8 +16,6 @@ fuck
|
|||
麻醉乙醚
|
||||
短信群发器
|
||||
帝国之梦
|
||||
毛一鲜
|
||||
黎阳平
|
||||
对日强硬
|
||||
出售枪支
|
||||
摇头丸
|
||||
|
@ -61,7 +31,6 @@ PK黑社会
|
|||
侦探设备
|
||||
麻醉钢枪
|
||||
反华
|
||||
官商勾结
|
||||
升达毕业证
|
||||
戴海静
|
||||
自杀指南
|
||||
|
@ -72,13 +41,8 @@ PK黑社会
|
|||
强效失意药
|
||||
迷奸药
|
||||
透视眼镜
|
||||
远程偷拍
|
||||
自制手枪
|
||||
激情小电影
|
||||
黄色小电影
|
||||
天鹅之旅
|
||||
盘古乐队
|
||||
高校暴乱
|
||||
高校群体事件
|
||||
大学骚乱
|
||||
高校骚乱
|
||||
|
@ -98,8 +62,6 @@ PK黑社会
|
|||
反政府
|
||||
禁书
|
||||
特码
|
||||
国民党
|
||||
贪污
|
||||
骚妇
|
||||
法论功
|
||||
江湖淫娘
|
||||
|
@ -152,24 +114,15 @@ AV
|
|||
玉蒲团
|
||||
隐形喷剂
|
||||
反雷达测速
|
||||
假币
|
||||
代开发票
|
||||
假钞
|
||||
窃听
|
||||
电话拦截系统
|
||||
探测狗
|
||||
手机卡复制器
|
||||
手机跟踪定位器
|
||||
监听器
|
||||
针孔摄像
|
||||
监听宝
|
||||
迷幻药
|
||||
手拍肩
|
||||
迷魂香
|
||||
麻古
|
||||
政治风波
|
||||
政府软弱
|
||||
政府无能
|
||||
九评
|
||||
十七大代表
|
||||
暴力拆迁
|
||||
|
@ -178,8 +131,6 @@ AV
|
|||
高干子弟名单
|
||||
性免费电影
|
||||
全裸
|
||||
偷拍
|
||||
中共十七大
|
||||
徐和柴学友
|
||||
修炼之歌
|
||||
警察殴打
|
||||
|
@ -187,7 +138,6 @@ AV
|
|||
李沛瑶遇害
|
||||
美国凯德
|
||||
肥东交警
|
||||
中央军委
|
||||
针对台湾
|
||||
梁保华
|
||||
MC军团
|
||||
|
@ -195,7 +145,6 @@ MC军团
|
|||
伪民运
|
||||
采花堂
|
||||
中国劳工通讯
|
||||
评中国共产党
|
||||
建立生活性补贴
|
||||
中共走狗
|
||||
中共小丑
|
||||
|
@ -236,7 +185,6 @@ A集中营
|
|||
江独裁
|
||||
李屠夫
|
||||
江恶人
|
||||
中共特务
|
||||
乙醚
|
||||
党内分裂
|
||||
圆明网
|
||||
|
@ -282,7 +230,6 @@ A集中营
|
|||
特务民运
|
||||
中共警察
|
||||
中共监狱
|
||||
中共政权
|
||||
中共迫害
|
||||
自由联邦
|
||||
中共独枭
|
||||
|
@ -307,9 +254,6 @@ H漫画
|
|||
买春堂
|
||||
苏东解体
|
||||
反右题材
|
||||
隐私图片
|
||||
卫星接收器
|
||||
卫星电视
|
||||
信号拦截器
|
||||
新闻通气会
|
||||
山西洪洞
|
||||
|
@ -427,35 +371,27 @@ H漫画
|
|||
毛爷爷复活
|
||||
智能H3
|
||||
智能H3
|
||||
赣江学院
|
||||
江西田园置业集团
|
||||
海乐神
|
||||
酣乐欣
|
||||
高莺莺
|
||||
完全自杀手册
|
||||
无界
|
||||
广东王
|
||||
口头检查
|
||||
三句硬话
|
||||
红海湾
|
||||
升达
|
||||
沈阳公安
|
||||
拦截器
|
||||
阻无通畅
|
||||
民为法执
|
||||
尾行
|
||||
电车之狼
|
||||
绕过封锁
|
||||
本拉登
|
||||
汕尾事件
|
||||
公务员工资
|
||||
公务员调资
|
||||
鸡吧
|
||||
公务员的工资
|
||||
反中游行
|
||||
支持台湾
|
||||
双鞋的故事
|
||||
中国军用运输机
|
||||
科技精英遇难
|
||||
湘阴杨林
|
||||
杨林寨
|
||||
|
@ -467,11 +403,8 @@ H漫画
|
|||
鬼村
|
||||
重题工
|
||||
先烈的电电
|
||||
身份证生成
|
||||
短信猫
|
||||
车牌反光
|
||||
次下跪
|
||||
求救遭拒
|
||||
邪恶的党
|
||||
出售迷药
|
||||
针孔摄像机
|
||||
|
@ -589,21 +522,8 @@ a级情片
|
|||
保钓
|
||||
鲍戈
|
||||
鲍彤
|
||||
暴乱
|
||||
暴政
|
||||
北韩
|
||||
藏独
|
||||
曹长青
|
||||
曹刚川
|
||||
陈炳基
|
||||
陈破空
|
||||
陈希同
|
||||
陈小同
|
||||
陈宣良
|
||||
陈一谘
|
||||
陈总统
|
||||
程铁军
|
||||
迟浩田
|
||||
持不同政见
|
||||
赤匪
|
||||
赤化
|
||||
|
@ -618,16 +538,11 @@ a级情片
|
|||
地下教会
|
||||
地下刊物
|
||||
电视流氓
|
||||
钓鱼岛
|
||||
丁关根
|
||||
丁子霖
|
||||
东北独立
|
||||
东社
|
||||
东土耳其斯坦
|
||||
东西南北论坛
|
||||
动乱
|
||||
独裁
|
||||
独裁政治
|
||||
独夫
|
||||
独立台湾会
|
||||
屙民
|
||||
|
@ -638,16 +553,11 @@ a级情片
|
|||
法仑
|
||||
法伦
|
||||
法轮
|
||||
法论
|
||||
反封锁技术
|
||||
反腐败论坛
|
||||
反共
|
||||
李洪志
|
||||
法轮功
|
||||
江泽民
|
||||
毛泽东
|
||||
邓小平
|
||||
胡锦涛
|
||||
推翻
|
||||
打倒
|
||||
台独
|
||||
|
@ -836,7 +746,6 @@ A片
|
|||
避孕套
|
||||
你妈逼
|
||||
大鸡巴
|
||||
政治
|
||||
卖春
|
||||
买春
|
||||
朱容基
|
||||
|
@ -869,7 +778,6 @@ A片
|
|||
吸储
|
||||
张五常
|
||||
张丕林
|
||||
空难
|
||||
吴邦国
|
||||
曾庆红
|
||||
黄菊
|
||||
|
@ -890,33 +798,19 @@ A片
|
|||
吳邦國
|
||||
曾慶紅
|
||||
賈慶林
|
||||
反人类
|
||||
反社会
|
||||
方励之
|
||||
方舟子
|
||||
斐得勒
|
||||
费良勇
|
||||
分家在
|
||||
分裂
|
||||
粉饰太平
|
||||
风雨神州
|
||||
风雨神州论坛
|
||||
封从德
|
||||
冯东海
|
||||
冯素英
|
||||
佛展千手法
|
||||
付申奇
|
||||
傅申奇
|
||||
傅志寰
|
||||
高文谦
|
||||
高薪养廉
|
||||
高瞻
|
||||
高自联
|
||||
鸽派
|
||||
个人崇拜
|
||||
工自联
|
||||
共产
|
||||
共党
|
||||
共匪
|
||||
共狗
|
||||
共军
|
||||
|
@ -925,8 +819,6 @@ A片
|
|||
郭伯雄
|
||||
郭罗基
|
||||
郭岩华
|
||||
国家安全
|
||||
国家机密
|
||||
国军
|
||||
国贼
|
||||
韩东方
|
||||
|
@ -985,49 +877,6 @@ A片
|
|||
抗议
|
||||
邝锦文
|
||||
劳动教养所
|
||||
劳改
|
||||
劳教
|
||||
老江
|
||||
老毛
|
||||
黎安友
|
||||
李洪宽
|
||||
李继耐
|
||||
李兰菊
|
||||
李少民
|
||||
李淑娴
|
||||
李旺阳
|
||||
李文斌
|
||||
李月月鸟
|
||||
李志绥
|
||||
连胜德
|
||||
廉政大论坛
|
||||
梁光烈
|
||||
梁擎墩
|
||||
两岸关系
|
||||
两岸三地论坛
|
||||
两个中国
|
||||
廖锡龙
|
||||
林保华
|
||||
林长盛
|
||||
林樵清
|
||||
林慎立
|
||||
刘宾深
|
||||
刘宾雁
|
||||
刘国凯
|
||||
刘华清
|
||||
刘俊国
|
||||
刘凯中
|
||||
刘千石
|
||||
刘山青
|
||||
刘士贤
|
||||
刘文胜
|
||||
刘晓波
|
||||
刘晓竹
|
||||
刘永川
|
||||
龙虎豹
|
||||
陆委会
|
||||
吕京花
|
||||
吕秀莲
|
||||
抡功
|
||||
轮大
|
||||
罗礼诗
|
||||
|
@ -1040,12 +889,8 @@ A片
|
|||
毛贼东
|
||||
美国参考
|
||||
美国之音
|
||||
蒙独
|
||||
蒙古独立
|
||||
密穴
|
||||
绵恒
|
||||
民国
|
||||
民进党
|
||||
民联
|
||||
民意
|
||||
民意论坛
|
||||
|
@ -1073,7 +918,6 @@ A片
|
|||
人民内情真相
|
||||
人民真实
|
||||
人民之声论坛
|
||||
人权
|
||||
善恶有报
|
||||
上海帮
|
||||
邵家健
|
||||
|
@ -1087,14 +931,6 @@ A片
|
|||
双十节
|
||||
水扁
|
||||
税力
|
||||
司马晋
|
||||
司马璐
|
||||
司徒华
|
||||
斯诺
|
||||
四川独立
|
||||
宋书元
|
||||
苏绍智
|
||||
苏晓康
|
||||
台盟
|
||||
台湾狗
|
||||
台湾建国运动组织
|
||||
|
@ -1129,17 +965,7 @@ A片
|
|||
王秀丽
|
||||
王冶坪
|
||||
网特
|
||||
魏新生
|
||||
温元凯
|
||||
文革
|
||||
无界浏览器
|
||||
吴百益
|
||||
吴方城
|
||||
吴弘达
|
||||
吴宏达
|
||||
吴仁华
|
||||
吴学灿
|
||||
吴学璨
|
||||
吾尔开希
|
||||
五不
|
||||
洗脑
|
||||
|
@ -1207,12 +1033,10 @@ A片
|
|||
正义党论坛
|
||||
换妻
|
||||
真木加美
|
||||
超爽
|
||||
毛片
|
||||
打手枪
|
||||
欲望
|
||||
脚交
|
||||
伦理
|
||||
艳星
|
||||
三陪
|
||||
绝色
|
||||
|
@ -1239,7 +1063,6 @@ A片
|
|||
天安门一代
|
||||
自民党
|
||||
自由民主论坛
|
||||
走私
|
||||
淫穴
|
||||
幼女
|
||||
舆论
|
||||
|
@ -1252,7 +1075,6 @@ fa轮
|
|||
指点江山论坛
|
||||
中俄边界
|
||||
中功
|
||||
中共
|
||||
中国威胁论
|
||||
中国问题论坛
|
||||
中国之春
|
||||
|
@ -1357,7 +1179,6 @@ B样
|
|||
淫图
|
||||
交媾
|
||||
护士
|
||||
自拍
|
||||
大片
|
||||
夫妻
|
||||
流血
|
||||
|
|
Binary file not shown.
|
@ -548,6 +548,7 @@ Rails.application.routes.draw do
|
|||
get :forks, to: 'projects#fork_users'
|
||||
match :about, :via => [:get, :put, :post]
|
||||
post :quit
|
||||
post :clone_detection
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -83,6 +83,10 @@ defaults format: :json do
|
|||
patch :update_phone
|
||||
end
|
||||
end
|
||||
scope module: :organizations do
|
||||
resources :sync_repositories, only: [:create]
|
||||
resources :projects, only: [:index]
|
||||
end
|
||||
scope module: :users do
|
||||
resources :projects, only: [:index]
|
||||
resources :feedbacks, only: [:create]
|
||||
|
@ -188,6 +192,7 @@ defaults format: :json do
|
|||
resources :runs, only: [:index, :create] do
|
||||
post '/jobs/:job', to: 'runs#job_show'
|
||||
post '/rerun', to: 'runs#rerun'
|
||||
post '/cancel', to: 'runs#cancel'
|
||||
post '/jobs/:job/rerun', to: 'runs#job_rerun'
|
||||
get '/jobs/:job/logs', to: 'runs#job_logs'
|
||||
end
|
||||
|
@ -203,6 +208,7 @@ defaults format: :json do
|
|||
resources :pulls, module: 'pulls' do
|
||||
member do
|
||||
get :files
|
||||
post :reopen
|
||||
end
|
||||
resources :versions, only: [:index] do
|
||||
member do
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddProjectIndexGpid < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_index :projects, :gpid
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue