Compare commits

...

121 Commits

Author SHA1 Message Date
yystopf 95f49450b0 新增:关联的疑修操作日志 2025-08-01 15:36:59 +08:00
yystopf bcf0b376a9 新增:关联的疑修操作日志 2025-08-01 15:25:47 +08:00
yystopf 81a5adb21a 新增:关联的疑修操作日志 2025-08-01 15:12:41 +08:00
yystopf b6de7fa96b fixed:操作日志为空的情况 2025-08-01 14:57:07 +08:00
yystopf 01ef87f5a3 fixed:操作日志为空的情况 2025-08-01 14:34:17 +08:00
yystopf a35537694c 修复:操作日志显示错误 2025-07-31 16:41:58 +08:00
yystopf 2229c732ca 新增:返回列表project_id 2025-07-30 16:48:30 +08:00
yystopf 532b924ff1 新增:返回列表project_id 2025-07-30 16:32:58 +08:00
yystopf 16a71a383b 更改:用户操作日志 2025-07-30 16:23:41 +08:00
xxq250 7d67defa24 fixed 流水线停止api 2025-07-29 10:59:30 +08:00
xxq250 41515575f1 add 流水线停止api 2025-07-29 10:33:56 +08:00
yystopf f4248ec14b fixed 2025-07-25 15:06:50 +08:00
yystopf 9544a5b22d fixed 2025-07-25 15:02:42 +08:00
yystopf 9cf4cc290c 更改:请求参数查询 2025-07-25 15:01:36 +08:00
yystopf e37d76d972 更改:请求参数查询 2025-07-25 14:58:08 +08:00
yystopf c18d1d2ce4 新增:组织项目查询路由 2025-07-25 14:53:03 +08:00
yystopf 40576e321f fixed 2025-07-25 14:50:27 +08:00
yystopf f9e7b92386 fixed 2025-07-25 14:48:50 +08:00
yystopf 40955f5a99 新增:组织下查询接口以及组织成员数 2025-07-25 14:46:21 +08:00
yystopf cece63286e 更改:排序正序倒序 2025-07-24 16:09:06 +08:00
yystopf debefe2e7c 新增:排序正序与倒序 2025-07-24 10:15:49 +08:00
yystopf ad2f42bed6 新增:排序正序与倒序 2025-07-24 10:13:43 +08:00
yystopf 473b9e3dfd 新增:负责人筛选 2025-07-24 09:59:45 +08:00
xxq250 655bb7bb4e add 敏感词调整 2025-07-23 13:55:15 +08:00
xxq250 da48040d2c Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-07-22 16:52:49 +08:00
xxq250 732a3a1405 add 敏感词调整 2025-07-22 16:52:42 +08:00
yystopf 31e4d73e2a 新增:周报时间筛选 2025-07-22 10:20:30 +08:00
xxq250 bd3dd5df4a add 敏感词调整 2025-07-21 15:16:13 +08:00
yystopf 85b55619c6 修复:最近提交文件数过多无法加载的问题 2025-07-18 21:08:28 +08:00
xxq250 9d968ac5db add 在线用户记录数单独显示 2025-07-18 14:59:27 +08:00
xxq250 a90bed0b8f add 在线用户记录,统计缓存取消 2025-07-18 14:20:29 +08:00
xxq250 4151b3564f add 在线用户记录,统计开关 2025-07-18 14:15:16 +08:00
xxq250 bff04758b8 add 在线用户记录,统计 2025-07-18 11:55:25 +08:00
xxq250 7f386622a3 add 在线用户记录,统计 2025-07-18 11:54:52 +08:00
xxq250 9d8600eb1c add 在线用户记录 2025-07-18 11:52:24 +08:00
xxq250 981dde45ef fixed 增加代码库文本内容显示敏感词检测3 2025-07-07 15:52:44 +08:00
xxq250 b02cf8fe79 fixed 增加代码库文本内容显示敏感词检测2 2025-07-07 15:47:13 +08:00
xxq250 44c8d0be7c fixed 增加代码库文本内容显示敏感词检测 2025-07-07 15:42:07 +08:00
xxq250 4afce7809d fixed 敏感词不显示,方法改为tip_exception 2025-07-07 15:26:48 +08:00
xxq250 10c05896fc fixed 敏感词不显示 2025-07-07 15:05:47 +08:00
xxq250 d260fcfe35 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-07-02 14:57:50 +08:00
xxq250 d286502224 fixed 用户搜组织增加名称模糊搜索 2025-07-02 14:57:44 +08:00
yystopf cabc9775bc 更改:导入同步项目失败处理 2025-07-02 14:56:27 +08:00
yystopf 8c9f6d6175 新增:同步github组织下项目 2025-07-01 16:19:15 +08:00
yystopf 0ae4f8decd Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2025-06-27 15:26:06 +08:00
yystopf a86372dc16 修复:周报报错 2025-06-27 15:25:59 +08:00
xxq250 3eebf61f03 fixed 项目表头像处理 2025-06-27 14:40:37 +08:00
xxq250 cf6dc3a9b4 fixed projects gpid 增加索引 2025-06-27 14:39:28 +08:00
yystopf 2a0ce2972a fixed: 返回错误跳转地址 2025-06-25 16:44:44 +08:00
yystopf 8cab37587e fixed: 返回错误跳转地址 2025-06-25 16:42:12 +08:00
yystopf 542fe0b60c fixed:同一方向pullrequest不允许存在 2025-06-25 16:12:58 +08:00
yystopf bb720d20c1 fixed:同一方向pullrequest不允许存在 2025-06-25 16:03:31 +08:00
KingChan 6bcdc20500 Merge pull request 'render pm_logo_url' (#402) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-25 10:02:06 +08:00
呱呱呱 5faf040862 update pm_logo_url render 2025-06-25 10:02:05 +08:00
KingChan 991a421b67 Merge pull request 'laboratory pm logo' (#401) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-25 09:43:58 +08:00
呱呱呱 74f928bab2 setting laboratory pm logo 2025-06-25 09:43:50 +08:00
yystopf 9cb7a22e52 fix: error返回 2025-06-24 14:21:33 +08:00
yystopf 6a7174781c 新增:重新打开pr接口 2025-06-23 19:27:47 +08:00
yystopf 880f547b3b 更改:继承模板 2025-06-21 15:42:57 +08:00
yystopf f97ad21af5 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2025-06-21 15:06:32 +08:00
yystopf 5230064b29 更改:解决加载过慢的问题以及child_count查询范围 2025-06-21 15:06:24 +08:00
xxq250 8fffa5530c Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-06-21 08:33:30 +08:00
yystopf 02df11cc64 更改:导入工作项默认创建者 2025-06-21 08:33:10 +08:00
yystopf ba2a76de8c 更改:导入工作项默认创建者 2025-06-20 15:09:26 +08:00
yystopf f1bf41c7f6 更改 trend project可以为空 2025-06-20 15:07:45 +08:00
yystopf 1a282dc925 fix: 用户导入导出按钮隐藏 2025-06-20 13:58:32 +08:00
yystopf 829e6bfe02 更改:未拥有权限去除新增按钮 2025-06-20 11:22:10 +08:00
yystopf c3754f65cd 更改:运营人员菜单权限 2025-06-20 10:32:01 +08:00
yystopf 16a64027f1 更改:运营人员菜单权限 2025-06-20 10:29:22 +08:00
yystopf e6eea663a9 更改:运营人员菜单权限 2025-06-20 10:25:24 +08:00
KingChan 52b46f4b89 Merge pull request 'update' (#396) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 16:46:10 +08:00
呱呱呱 e7795faa22 update 2025-06-19 16:46:03 +08:00
KingChan 831576d4aa Merge pull request 'admin端删除组织记录渲染组织信息' (#395) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 16:39:34 +08:00
呱呱呱 2b9e53565a admin user action DestroyOrganization render 2025-06-19 16:39:24 +08:00
KingChan 76d3c29c42 Merge pull request '修复删除bug' (#394) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 16:27:45 +08:00
呱呱呱 346b815e0a fix bug 2025-06-19 16:27:33 +08:00
KingChan 7496a4bdd6 Merge pull request '增加用户删除组织时创建记录' (#393) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 16:24:35 +08:00
呱呱呱 470064ecd5 add Organization destroy create action 2025-06-19 16:24:02 +08:00
KingChan 974213ff59 Merge pull request '修复删除组织时记录组织信息没被记录的问题' (#392) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 15:54:36 +08:00
呱呱呱 b52aa0633e user action DestroyOrganization data_bank 2025-06-19 15:54:02 +08:00
xxq250 76545cf72f add 克隆检测 2025-06-19 14:10:16 +08:00
KingChan 14350f6812 Merge pull request '调整百度统计计算方法' (#391) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-19 09:49:50 +08:00
呱呱呱 0bc702b957 fix baidu tongji bug 2025-06-19 09:49:35 +08:00
KingChan d5b0fccf03 Merge pull request '调整bing网站的统计数据' (#390) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-18 14:56:30 +08:00
呱呱呱 2ff38ad402 update bing from link to search 2025-06-18 14:56:13 +08:00
KingChan 63593535a7 Merge pull request 'my_issues 增加按照创建时间倒序' (#389) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-18 10:34:10 +08:00
呱呱呱 f767d95730 pm my_issues add order desc 2025-06-18 10:33:42 +08:00
KingChan e317fafb89 Merge pull request 'task 128017 管理员界面增加删除组织下拉菜单' (#388) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-18 10:10:26 +08:00
呱呱呱 27d73f0c11 add admin user_action view filter 2025-06-18 10:09:46 +08:00
xxq250 a8f06eb022 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-06-17 11:17:28 +08:00
xxq250 6598eb6b76 fixed 登录更新时间5分钟写入一次 2025-06-17 11:17:21 +08:00
yystopf c97188aff8 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2025-06-09 14:09:26 +08:00
yystopf 7d466217c7 更改:查询本周和下周工作项需要增加时间参数 2025-06-09 14:09:14 +08:00
KingChan d86d7f5d3e Merge pull request 'update sonar' (#386) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 16:42:46 +08:00
呱呱呱 a2ab42f392 update 2025-06-07 16:42:38 +08:00
KingChan a3517e651f Merge pull request 'update sonar' (#384) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 16:27:25 +08:00
呱呱呱 3e859e4469 fix sonar exec error 2025-06-07 16:27:06 +08:00
KingChan 74706ab7a2 Merge pull request 'update sonar' (#382) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 16:00:48 +08:00
呱呱呱 8fa20c7f6b java sonar 2025-06-07 16:00:14 +08:00
xxq250 f96bcfa162 Merge remote-tracking branch 'origin/standalone_develop' into standalone_develop 2025-06-07 15:01:47 +08:00
xxq250 145463f967 fixed 流水线删除时删除运行记录错误 2025-06-07 15:01:40 +08:00
yystopf 6a6698bc74 Merge branch 'standalone_develop' of https://gitlink.org.cn/Trustie/forgeplus into standalone_develop 2025-06-07 14:51:02 +08:00
yystopf 41cbeae2f7 更改:查看我负责或组织工作项需要按层级展示 2025-06-07 14:48:48 +08:00
KingChan 9645f38e31 Merge pull request 'update sonar' (#380) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 14:27:29 +08:00
呱呱呱 fa26098426 update sonar 2025-06-07 14:27:20 +08:00
KingChan 6c937e6af6 Merge pull request 'update sonar' (#375) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 11:54:52 +08:00
呱呱呱 ef06a808a9 fix sonar 2025-06-07 11:54:45 +08:00
KingChan 6d51061f49 Merge pull request 'update sonar' (#373) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 11:13:41 +08:00
呱呱呱 4eaf5aada2 update sonar 2025-06-07 11:12:48 +08:00
KingChan fb461b2fe6 Merge pull request 'update sonar' (#371) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 10:51:25 +08:00
呱呱呱 045d324809 update sonar 2025-06-07 10:51:09 +08:00
KingChan e03e011f18 Merge pull request 'update sonar' (#369) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 10:41:46 +08:00
呱呱呱 055e916d08 update 2025-06-07 10:39:25 +08:00
KingChan 37e28fdf2e Merge pull request 'update sonar' (#367) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 10:32:37 +08:00
呱呱呱 1a755048bb update 2025-06-07 10:32:02 +08:00
KingChan fcabd83a9d Merge pull request 'update' (#365) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 10:13:26 +08:00
呱呱呱 387f33b2b0 update 2025-06-07 10:13:11 +08:00
KingChan c0e6720cd4 Merge pull request 'update sonar' (#363) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 09:31:58 +08:00
呱呱呱 737b6bc18f update 2025-06-07 09:31:46 +08:00
KingChan 616e99cc86 Merge pull request 'update sonar' (#361) from KingChan/forgeplus:standalone_develop into standalone_develop 2025-06-07 08:46:52 +08:00
呱呱呱 ee47f29264 sonar 2025-06-07 08:46:35 +08:00
76 changed files with 797 additions and 355 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}})

View File

@ -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

View File

@ -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

View File

@ -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/")

View File

@ -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

View File

@ -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

View File

@ -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("当组织内含有仓库时,无法删除此组织")

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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")

89
app/libs/user_online.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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|

View File

@ -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')

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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">

View File

@ -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>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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">

View File

@ -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 %>

View File

@ -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">

View File

@ -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 %>

View File

@ -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">

View File

@ -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 %>

View File

@ -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">

View File

@ -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 %>

View File

@ -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>

View File

@ -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>

View File

@ -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: '操作人用户名/邮箱/手机号检索') %>

View File

@ -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">

View File

@ -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 %>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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样
淫图
交媾
护士
自拍
大片
夫妻
流血

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,5 @@
class AddProjectIndexGpid < ActiveRecord::Migration[5.2]
def change
add_index :projects, :gpid
end
end