Browse Source

Merge pull request '20220722版本' (#309) from Trustie/forgeplus:trustie_server into master

pull/329/head
xxq250 3 years ago
parent
commit
802568cf89
100 changed files with 3844 additions and 913 deletions
  1. +138
    -130
      Gemfile
  2. +7
    -0
      Gemfile.lock
  3. +33
    -7
      app/controllers/admins/dashboards_controller.rb
  4. +47
    -0
      app/controllers/api/v1/base_controller.rb
  5. +18
    -0
      app/controllers/api/v1/projects/branches_controller.rb
  6. +12
    -0
      app/controllers/api/v1/projects/commits_controller.rb
  7. +13
    -0
      app/controllers/api/v1/projects/contents_controller.rb
  8. +12
    -0
      app/controllers/api/v1/projects/git_controller.rb
  9. +55
    -0
      app/controllers/api/v1/projects/webhooks_controller.rb
  10. +20
    -0
      app/controllers/api/v1/projects_controller.rb
  11. +13
    -0
      app/controllers/api/v1/users/projects_controller.rb
  12. +6
    -0
      app/controllers/api/v1/users_controller.rb
  13. +47
    -32
      app/controllers/application_controller.rb
  14. +2
    -2
      app/controllers/attachments_controller.rb
  15. +27
    -0
      app/controllers/commit_logs_controller.rb
  16. +8
    -3
      app/controllers/compare_controller.rb
  17. +3
    -3
      app/controllers/concerns/acceleratorable.rb
  18. +20
    -0
      app/controllers/concerns/api/project_helper.rb
  19. +19
    -0
      app/controllers/concerns/api/user_helper.rb
  20. +1
    -0
      app/controllers/concerns/login_helper.rb
  21. +10
    -1
      app/controllers/concerns/repository/languages_percentagable.rb
  22. +39
    -0
      app/controllers/oauth2_controller.rb
  23. +42
    -0
      app/controllers/projects/project_invite_links_controller.rb
  24. +7
    -1
      app/controllers/pull_requests_controller.rb
  25. +8
    -8
      app/controllers/repositories_controller.rb
  26. +20
    -0
      app/controllers/reviews_controller.rb
  27. +11
    -5
      app/controllers/traces/projects_controller.rb
  28. +1
    -1
      app/controllers/users_controller.rb
  29. +5
    -5
      app/docs/slate/source/api.html.md
  30. +274
    -0
      app/docs/slate/source/includes/_projects.md
  31. +1201
    -254
      app/docs/slate/source/includes/_repositories.md
  32. +99
    -0
      app/docs/slate/source/includes/_users.md
  33. +8
    -0
      app/forms/projects/project_invite_links/create_form.rb
  34. +1
    -1
      app/helpers/projects_helper.rb
  35. +217
    -218
      app/helpers/repositories_helper.rb
  36. +2
    -2
      app/interactors/gitea/register_interactor.rb
  37. +1
    -1
      app/libs/ci/drone/server.rb
  38. +1
    -1
      app/libs/gitea_service.rb
  39. +12
    -9
      app/models/applied_project.rb
  40. +6
    -0
      app/models/commit_log.rb
  41. +1
    -0
      app/models/issue.rb
  42. +2
    -0
      app/models/journal.rb
  43. +1
    -0
      app/models/message_template/custom_tip.rb
  44. +4
    -3
      app/models/project.rb
  45. +59
    -0
      app/models/project_invite_link.rb
  46. +1
    -0
      app/models/project_unit.rb
  47. +27
    -0
      app/models/review.rb
  48. +18
    -2
      app/models/user.rb
  49. +38
    -0
      app/services/api/v1/projects/blame_service.rb
  50. +30
    -0
      app/services/api/v1/projects/branches/all_list_service.rb
  51. +51
    -0
      app/services/api/v1/projects/branches/create_service.rb
  52. +36
    -0
      app/services/api/v1/projects/commits/diff_service.rb
  53. +38
    -0
      app/services/api/v1/projects/commits/list_service.rb
  54. +34
    -0
      app/services/api/v1/projects/compare_service.rb
  55. +91
    -0
      app/services/api/v1/projects/contents/batch_create_service.rb
  56. +50
    -0
      app/services/api/v1/projects/get_service.rb
  57. +34
    -0
      app/services/api/v1/projects/git/blobs_service.rb
  58. +52
    -0
      app/services/api/v1/projects/git/trees_service.rb
  59. +40
    -0
      app/services/api/v1/projects/pull_requests/reviews/create_service.rb
  60. +62
    -0
      app/services/api/v1/projects/webhooks/create_service.rb
  61. +32
    -0
      app/services/api/v1/projects/webhooks/delete_service.rb
  62. +33
    -0
      app/services/api/v1/projects/webhooks/get_service.rb
  63. +35
    -0
      app/services/api/v1/projects/webhooks/hooktasks_service.rb
  64. +31
    -0
      app/services/api/v1/projects/webhooks/list_service.rb
  65. +32
    -0
      app/services/api/v1/projects/webhooks/tests_service.rb
  66. +63
    -0
      app/services/api/v1/projects/webhooks/update_service.rb
  67. +86
    -0
      app/services/api/v1/users/projects/list_service.rb
  68. +1
    -1
      app/services/educoder/client_service.rb
  69. +1
    -1
      app/services/gitea/accelerator/base_service.rb
  70. +2
    -2
      app/services/gitea/client_service.rb
  71. +2
    -2
      app/services/gitea/user/delete_service.rb
  72. +1
    -1
      app/services/gitea/user/update_service.rb
  73. +86
    -0
      app/services/projects/link_join_service.rb
  74. +1
    -1
      app/services/repositories/create_service.rb
  75. +12
    -3
      app/services/trace/pdf_report_service.rb
  76. +53
    -213
      app/views/admins/dashboards/index.html.erb
  77. +10
    -0
      app/views/api/v1/projects/_simple_detail.json.jbuilder
  78. +40
    -0
      app/views/api/v1/projects/_simple_gitea_diff_detail.json.jbuilder
  79. +22
    -0
      app/views/api/v1/projects/blame.json.jbuilder
  80. +4
    -0
      app/views/api/v1/projects/branches/_simple_detail.json.jbuilder
  81. +26
    -0
      app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder
  82. +3
    -0
      app/views/api/v1/projects/branches/all.json.jbuilder
  83. +1
    -0
      app/views/api/v1/projects/branches/create.json.jbuilder
  84. +10
    -0
      app/views/api/v1/projects/commits/_simple_gitea_detail.json.jbuilder
  85. +1
    -0
      app/views/api/v1/projects/commits/diff.json.jbuilder
  86. +17
    -0
      app/views/api/v1/projects/commits/index.json.jbuilder
  87. +18
    -0
      app/views/api/v1/projects/compare.json.jbuilder
  88. +14
    -0
      app/views/api/v1/projects/contents/batch.json.jbuilder
  89. +4
    -0
      app/views/api/v1/projects/git/blobs.json.jbuilder
  90. +9
    -0
      app/views/api/v1/projects/git/trees.json.jbuilder
  91. +5
    -0
      app/views/api/v1/projects/show.json.jbuilder
  92. +3
    -0
      app/views/api/v1/projects/webhooks/_simple_detail.json.jbuilder
  93. +8
    -0
      app/views/api/v1/projects/webhooks/_simple_gitea_detail.json.jbuilder
  94. +1
    -0
      app/views/api/v1/projects/webhooks/create.json.jbuilder
  95. +6
    -0
      app/views/api/v1/projects/webhooks/hooktasks.json.jbuilder
  96. +4
    -0
      app/views/api/v1/projects/webhooks/index.json.jbuilder
  97. +1
    -0
      app/views/api/v1/projects/webhooks/show.json.jbuilder
  98. +1
    -0
      app/views/api/v1/projects/webhooks/update.json.jbuilder
  99. +21
    -0
      app/views/api/v1/users/_commit_user.json.jbuilder
  100. +9
    -0
      app/views/api/v1/users/_simple_user.json.jbuilder

+ 138
- 130
Gemfile View File

@@ -1,130 +1,138 @@
source 'https://gems.ruby-china.com'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
# gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'groupdate', '~> 4.1.0'
gem 'chartkick'
gem 'grape-entity', '~> 0.7.1'
gem 'kaminari', '~> 1.1', '>= 1.1.1'
gem 'bootsnap', '>= 1.1.0', require: false
gem 'chinese_pinyin'
gem 'rack-cors'
gem 'redis-rails'
gem 'roo-xls'
gem 'simple_xlsx_reader'
gem 'rubyzip'
gem 'spreadsheet'
gem 'ruby-ole'
# 导出为xlsx
gem 'axlsx', '~> 3.0.0.pre'
gem 'axlsx_rails', '~> 0.5.2'
gem 'oauth2'
#导出为pdf
gem 'pdfkit'
gem 'wkhtmltopdf-binary'
# gem 'request_store'
#gem 'iconv'
# markdown 转html
gem 'redcarpet', '~> 3.4'
gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png'
gem 'acts-as-taggable-on', '~> 6.0'
# a tree structure
gem 'ancestry'
gem 'acts_as_list'
gem 'omniauth-cas'
# profiler Middleware
gem 'rack-mini-profiler'
# object-based searching
gem 'ransack'
group :development, :test do
gem 'rspec-rails', '~> 3.8'
end
group :development do
gem 'prettier'
gem 'rubocop', '~> 0.52.0'
gem 'solargraph', '~> 0.38.0'
gem 'awesome_print'
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0"
end
group :test do
gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver'
gem 'chromedriver-helper'
end
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
#编码检测
gem 'rchardet', '~> 1.8'
# http client
gem 'faraday', '~> 0.15.4'
# view
gem 'active_decorator'
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
gem 'simple_form'
gem 'font-awesome-sass', '4.7.0'
# i18n
gem 'rails-i18n', '~> 5.1'
# job
gem 'sidekiq'
gem 'sinatra'
gem "sidekiq-cron", "~> 1.1"
# batch insert
gem 'bulk_insert'
# elasticsearch
gem 'searchkick'
gem 'aasm'
gem 'enumerize'
gem 'diffy'
gem 'deep_cloneable', '~> 3.0.0'
# oauth2
gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'
# global var
gem 'request_store'
# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'
gem 'parallel', '~> 1.19', '>= 1.19.1'
gem 'letter_avatar'
source 'https://gems.ruby-china.com'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem 'rails', '~> 5.2.0'
gem 'mysql2', '>= 0.4.4', '< 0.6.0'
gem 'puma', '~> 3.11'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'

# gem 'coffee-rails', '~> 4.2'
gem 'turbolinks', '~> 5'
gem 'jbuilder', '~> 2.5'
gem 'groupdate', '~> 4.1.0'
gem 'chartkick'
gem 'grape-entity', '~> 0.7.1'
gem 'kaminari', '~> 1.1', '>= 1.1.1'

gem 'bootsnap', '>= 1.1.0', require: false

gem 'chinese_pinyin'

gem 'rack-cors'
gem 'redis-rails'
gem 'roo-xls'
gem 'simple_xlsx_reader'

gem 'rubyzip'

gem 'spreadsheet'
gem 'ruby-ole'
# 导出为xlsx
gem 'axlsx', '~> 3.0.0.pre'
gem 'axlsx_rails', '~> 0.5.2'

gem 'oauth2'
#导出为pdf
gem 'pdfkit'
gem 'wkhtmltopdf-binary'
# gem 'request_store'
#gem 'iconv'
# markdown 转html
gem 'redcarpet', '~> 3.4'

gem 'rqrcode', '~> 0.10.1'
gem 'rqrcode_png'

gem 'acts-as-taggable-on', '~> 6.0'

# a tree structure
gem 'ancestry'
gem 'acts_as_list'
gem 'omniauth-cas'

# profiler Middleware
gem 'rack-mini-profiler'

# object-based searching
gem 'ransack'

group :development, :test do
gem 'rspec-rails', '~> 3.8'
end

group :development do
gem 'prettier'
gem 'rubocop', '~> 0.52.0'
gem 'solargraph', '~> 0.38.0'
gem 'awesome_print'
gem 'web-console', '>= 3.3.0'
gem 'listen', '>= 3.0.5', '< 3.2'
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem "annotate", "~> 2.6.0"
end

group :test do
gem 'capybara', '>= 2.15', '< 4.0'
gem 'selenium-webdriver'
gem 'chromedriver-helper'
end

gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

#编码检测
gem 'rchardet', '~> 1.8'

# http client
gem 'faraday', '~> 0.15.4'

# view
gem 'active_decorator'
gem 'bootstrap', '~> 4.3.1'
gem 'jquery-rails'
gem 'simple_form'
gem 'font-awesome-sass', '4.7.0'

# i18n
gem 'rails-i18n', '~> 5.1'

# job
gem 'sidekiq'
gem 'sinatra'
gem "sidekiq-cron", "~> 1.1"

# batch insert
gem 'bulk_insert'

# elasticsearch
gem 'searchkick'

gem 'aasm'
gem 'enumerize'

gem 'diffy'

gem 'deep_cloneable', '~> 3.0.0'

# oauth2
gem 'omniauth', '~> 1.9.0'
gem 'omniauth-oauth2', '~> 1.6.0'

# global var
gem 'request_store'

# 敏感词汇
gem 'harmonious_dictionary', '~> 0.0.1'

gem 'parallel', '~> 1.19', '>= 1.19.1'

gem 'letter_avatar'

gem 'jwt'

gem 'doorkeeper'

gem 'doorkeeper-jwt'

gem 'gitea-client', '~> 0.10.2'

+ 7
- 0
Gemfile.lock View File

@@ -106,6 +106,10 @@ GEM
activerecord (>= 3.1.0, < 7)
diff-lcs (1.3)
diffy (3.3.0)
doorkeeper (5.5.1)
railties (>= 5)
doorkeeper-jwt (0.4.1)
jwt (>= 2.1)
e2mmap (0.1.0)
elasticsearch (7.5.0)
elasticsearch-api (= 7.5.0)
@@ -450,6 +454,8 @@ DEPENDENCIES
chromedriver-helper
deep_cloneable (~> 3.0.0)
diffy
doorkeeper
doorkeeper-jwt
enumerize
faraday (~> 0.15.4)
font-awesome-sass (= 4.7.0)
@@ -458,6 +464,7 @@ DEPENDENCIES
harmonious_dictionary (~> 0.0.1)
jbuilder (~> 2.5)
jquery-rails
jwt
kaminari (~> 1.1, >= 1.1.1)
letter_avatar
listen (>= 3.0.5, < 3.2)


+ 33
- 7
app/controllers/admins/dashboards_controller.rb View File

@@ -1,10 +1,33 @@
class Admins::DashboardsController < Admins::BaseController
def index
@active_user_count = User.where(last_login_on: today).count
@weekly_active_user_count = User.where(last_login_on: current_week).count
@month_active_user_count = User.where(last_login_on: current_month).count
# 用户活跃数
day_user_ids = CommitLog.where(created_at: today).pluck(:project_id).uniq
weekly_user_ids = CommitLog.where(created_at: current_week).pluck(:project_id).uniq
month_user_ids = CommitLog.where(created_at: current_month).pluck(:project_id).uniq
@active_user_count = User.where(last_login_on: today).or(User.where(id: day_user_ids)).count
@weekly_active_user_count = User.where(last_login_on: current_week).or(User.where(id: weekly_user_ids)).count
@month_active_user_count = User.where(last_login_on: current_month).or(User.where(id: month_user_ids)).count
user_ids = User.where(created_on: pre_week).pluck(:id).uniq
weekly_keep_user_count = User.where(id: user_ids).where(last_login_on: current_week).count
@weekly_keep_rate = format("%.2f", user_ids.size > 0 ? weekly_keep_user_count.to_f / user_ids.size : 0)

@new_user_count = User.where(created_on: current_month).count
# 新用户注册数
@day_new_user_count = User.where(created_on: today).count
@weekly_new_user_count = User.where(created_on: current_week).count
@month_new_user_count = User.where(created_on: current_month).count

# 活跃项目数
day_project_ids = (CommitLog.where(created_at: today).pluck(:project_id).uniq + Issue.where(created_on: today).pluck(:project_id).uniq).uniq
weekly_project_ids = (CommitLog.where(created_at: current_week).pluck(:project_id).uniq + Issue.where(created_on: current_week).pluck(:project_id).uniq).uniq
month_project_ids = (CommitLog.where(created_at: current_month).pluck(:project_id).uniq + Issue.where(created_on: current_month).pluck(:project_id).uniq).uniq
@day_active_project_count = Project.where(updated_on: today).or(Project.where(id: day_project_ids)).count
@weekly_active_project_count = Project.where(updated_on: current_week).or(Project.where(id: weekly_project_ids)).count
@month_active_project_count = Project.where(updated_on: current_month).or(Project.where(id: month_project_ids)).count

# 新增项目数
@day_new_project_count = Project.where(created_on: today).count
@weekly_new_project_count = Project.where(created_on: current_week).count
@month_new_project_count = Project.where(created_on: current_month).count
end

def month_active_user
@@ -16,7 +39,6 @@ class Admins::DashboardsController < Admins::BaseController
{ value: count['professional'].to_i, name: '专业人士' },
{ value: count[nil].to_i, name: '未选职业' },
]

render_ok(data: data)
end

@@ -42,10 +64,14 @@ class Admins::DashboardsController < Admins::BaseController
end

def current_week
7.days.ago.beginning_of_day..Time.now.end_of_day
7.days.ago.end_of_day..Time.now.end_of_day
end

def current_month
30.days.ago.beginning_of_day..Time.now.end_of_day
30.days.ago.end_of_day..Time.now.end_of_day
end

def pre_week
14.days.ago.end_of_day..7.days.ago.end_of_day
end
end

+ 47
- 0
app/controllers/api/v1/base_controller.rb View File

@@ -0,0 +1,47 @@
class Api::V1::BaseController < ApplicationController

include Api::ProjectHelper
include Api::UserHelper

# before_action :doorkeeper_authorize!
# skip_before_action :user_setup

protected
# def current_user
# #client方法对接,需要一直带着用户标识uid
# Rails.logger.info doorkeeper_token
# if doorkeeper_token && doorkeeper_token.resource_owner_id.blank?
# # return User.anonymous if params[:uid].nil?
# # tip_exception("2222")
# # return render_error('缺少用户标识!') if params[:uid].nil?
# User.current = User.find(params[:uid])
# else
# User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
# end
# end
def limit
params.fetch(:limit, 15)
end
def page
params.fetch(:page, 1)
end

# 具有对仓库的管理权限
def require_manager_above
@project = load_project
return render_forbidden unless current_user.admin? && @project.manager?(current_user)
end

# 具有对仓库的操作权限
def require_operate_above
@project = load_project
return render_forbidden unless current_user.admin? && @project.operator?(current_user)
end

# 具有对仓库的访问权限
def require_public_and_member_above
@project = load_project
return render_forbidden unless @project.is_public || (current_user.admin? && @project.member?(current_user))
end
end

+ 18
- 0
app/controllers/api/v1/projects/branches_controller.rb View File

@@ -0,0 +1,18 @@
class Api::V1::Projects::BranchesController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:all]

def all
@result_object = Api::V1::Projects::Branches::AllListService.call(@project, current_user&.gitea_token)
end

before_action :require_operate_above, only: [:create]

def create
@result_object = Api::V1::Projects::Branches::CreateService.call(@project, branch_params, current_user&.gitea_token)
end

private
def branch_params
params.require(:branch).permit(:new_branch_name, :old_branch_name)
end
end

+ 12
- 0
app/controllers/api/v1/projects/commits_controller.rb View File

@@ -0,0 +1,12 @@
class Api::V1::Projects::CommitsController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:index, :diff]

def index
@result_object = Api::V1::Projects::Commits::ListService.call(@project, {page: page, limit: limit, sha: params[:sha]}, current_user&.gitea_token)
puts @result_object
end

def diff
@result_object = Api::V1::Projects::Commits::DiffService.call(@project, params[:sha], current_user&.gitea_token)
end
end

+ 13
- 0
app/controllers/api/v1/projects/contents_controller.rb View File

@@ -0,0 +1,13 @@
class Api::V1::Projects::ContentsController < Api::V1::BaseController
before_action :require_operate_above, only: [:batch]

def batch
@result_object = Api::V1::Projects::Contents::BatchCreateService.call(@project, batch_content_params, current_user&.gitea_token)
puts @result_object
end

private
def batch_content_params
params.require(:content).permit(:author_email, :author_name, :author_timeunix, :branch, :committer_email, :committer_name, :committer_timeunix, :message, :new_branch, files: [ :action_type, :content, :encoding, :file_path])
end
end

+ 12
- 0
app/controllers/api/v1/projects/git_controller.rb View File

@@ -0,0 +1,12 @@
class Api::V1::Projects::GitController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:trees, :blobs]

def trees
@result_object = Api::V1::Projects::Git::TreesService.call(@project, params[:sha], {recursive: params[:recursive], page: page, limit: limit}, current_user&.gitea_token)
end

def blobs
@result_object = Api::V1::Projects::Git::BlobsService.call(@project, params[:sha], current_user&.gitea_token)
end

end

+ 55
- 0
app/controllers/api/v1/projects/webhooks_controller.rb View File

@@ -0,0 +1,55 @@
class Api::V1::Projects::WebhooksController < Api::V1::BaseController
before_action :require_manager_above
before_action :find_webhook, only: [:show, :update, :destroy, :tests, :hooktasks]

def index
# @result_object = Api::V1::Projects::Webhooks::ListService.call(@project, current_user&.gitea_token)
@webhooks = @project.webhooks
@webhooks = kaminari_paginate(@webhooks)
end

def create
@result_object = Api::V1::Projects::Webhooks::CreateService.call(@project, webhook_params, current_user&.gitea_token)
end

def show
@result_object = Api::V1::Projects::Webhooks::GetService.call(@project, params[:id], current_user&.gitea_token)
end

def update
@result_object = Api::V1::Projects::Webhooks::UpdateService.call(@project, params[:id], webhook_params, current_user&.gitea_token)
end

def destroy
@result_object = Api::V1::Projects::Webhooks::DeleteService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('删除失败!')
end
end

def tests
@result_object = Api::V1::Projects::Webhooks::TestsService.call(@project, params[:id], current_user&.gitea_token)
if @result_object
return render_ok
else
return render_error('推送失败!')
end
end

def hooktasks
@hooktasks = @webhook.tasks.where(is_delivered: true).order("delivered desc")
@hooktasks = kaminari_paginate(@hooktasks)
end

private
def webhook_params
params.require(:webhook).permit(:active, :branch_filter, :http_method, :url, :content_type, :secret, events: [])
end

def find_webhook
@webhook = Gitea::Webhook.find_by_id(params[:id])
return render_not_found unless @webhook.present?
end
end

+ 20
- 0
app/controllers/api/v1/projects_controller.rb View File

@@ -0,0 +1,20 @@
class Api::V1::ProjectsController < Api::V1::BaseController
before_action :require_public_and_member_above, only: [:show, :compare, :blame]

def index
render_ok
end

def show
@result_object = Api::V1::Projects::GetService.call(@project, current_user.gitea_token)
end

def compare
@result_object = Api::V1::Projects::CompareService.call(@project, params[:from], params[:to], current_user&.gitea_token)
end

def blame
@result_object = Api::V1::Projects::BlameService.call(@project, params[:sha], params[:filepath], current_user&.gitea_token)
puts @result_object
end
end

+ 13
- 0
app/controllers/api/v1/users/projects_controller.rb View File

@@ -0,0 +1,13 @@
class Api::V1::Users::ProjectsController < Api::V1::BaseController
before_action :load_observe_user

def index
@object_results = Api::V1::Users::Projects::ListService.call(@observe_user, query_params, current_user)
@projects = kaminari_paginate(@object_results)
end

private
def query_params
params.permit(:category, :is_public, :project_type, :sort_by, :sort_direction, :search)
end
end

+ 6
- 0
app/controllers/api/v1/users_controller.rb View File

@@ -0,0 +1,6 @@
class Api::V1::UsersController < Api::V1::BaseController

def index
render_ok
end
end

+ 47
- 32
app/controllers/application_controller.rb View File

@@ -170,7 +170,6 @@ class ApplicationController < ActionController::Base
# 未授权的捕捉407,弹试用申请弹框
def require_login
#6.13 -hs

tip_exception(401, "请登录后再操作") unless User.current.logged?
end

@@ -249,39 +248,55 @@ class ApplicationController < ActionController::Base
#return if params[:controller] == "main"
# Find the current user
#Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}")
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)
if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer')
tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token?
if @doorkeeper_token.present?
# client方法对接,需要一直带着用户标识uid
if @doorkeeper_token.resource_owner_id.blank?
tip_exception(-1, "缺少用户标识!") if params[:uid].nil?
User.current = User.find(params[:uid])
else
User.current = User.find_by(id: @doorkeeper_token.resource_owner_id)
end
end
else
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
User.current = user
end
end
# if !User.current.logged? && Rails.env.development?
# User.current = User.find 1
# end


# 测试版前端需求
logger.info("subdomain:#{request.subdomain}")
if request.subdomain != "www"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
user = User.find 36480
User.current = user
cookies.signed[:user_id] = user.id
# if !User.current.logged? && Rails.env.development?
# user = User.find 1
# User.current = user
# start_user_session(user)
# end


# 测试版前端需求
logger.info("subdomain:#{request.subdomain}")
if request.subdomain != "www"
if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除
User.current = User.find 81403
elsif params[:debug] == 'student'
User.current = User.find 8686
elsif params[:debug] == 'admin'
logger.info "@@@@@@@@@@@@@@@@@@@@@@ debug mode....."
user = User.find 36480
User.current = user
cookies.signed[:user_id] = user.id
end
end
end
# User.current = User.find 81403
@@ -681,7 +696,7 @@ class ApplicationController < ActionController::Base

@project, @owner = Project.find_with_namespace(namespace, id)

if @project and current_user.can_read_project?(@project)
if @project and (current_user.can_read_project?(@project) || controller_path == "projects/project_invite_links")
logger.info "###########: has project and can read project"
@project
# elsif @project && current_user.is_a?(AnonymousUser)


+ 2
- 2
app/controllers/attachments_controller.rb View File

@@ -33,8 +33,8 @@ class AttachmentsController < ApplicationController
normal_status(-1, "参数缺失") if params[:download_url].blank?
url = URI.encode(params[:download_url].to_s.gsub("http:", "https:"))
if url.starts_with?(base_url)
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
domain = GiteaService.gitea_config[:domain]
api_url = GiteaService.gitea_config[:base_url]
url = url.split(base_url)[1].gsub("api", "repos").gsub('?filepath=', '/').gsub('&', '?')
request_url = [domain, api_url, url, "?ref=#{params[:ref]}&access_token=#{current_user&.gitea_token}"].join
response = Faraday.get(request_url)


+ 27
- 0
app/controllers/commit_logs_controller.rb View File

@@ -0,0 +1,27 @@
class CommitLogsController < ApplicationController

def create
tip_exception "未认证" unless params[:token].to_s == "7917908927b6f1b792f2027a08a8b24a2de42c1692c2fd45da0dee5cf90a5af5"
ref = params[:ref]
user_name = params[:pusher][:login]
user_mail = params[:pusher][:email]
user = User.find_by(mail: user_mail)
user = User.find_by(login: user_name) if user.blank?

repository_id = params[:repository][:id]
repository_name = params[:repository][:name]
repository_full_name = params[:repository][:full_name]
owner_name = repository_full_name.split("/")[0]
owner = User.find_by(login: owner_name)
project = Project.where(identifier: repository_name).where(user_id: owner&.id)&.first
project = Project.where(identifier: repository_name).where(gpid: repository_id)&.first if project.blank?
params[:commits].each do |commit|
commit_id = commit[:id]
message = commit[:message]
CommitLog.create(user: user, project: project, repository_id: repository_id,
name: repository_name, full_name: repository_full_name,
ref: ref, commit_id: commit_id, message: message)
end

end
end

+ 8
- 3
app/controllers/compare_controller.rb View File

@@ -6,9 +6,14 @@ class CompareController < ApplicationController
end

def show
load_compare_params
compare
@merge_status, @merge_message = get_merge_message
if params[:type] == "sha"
load_compare_params
@compare_result ||= gitea_compare(@base, @head)
else
load_compare_params
compare
@merge_status, @merge_message = get_merge_message
end
@page_size = page_size <= 0 ? 1 : page_size
@page_limit = page_limit <=0 ? 15 : page_limit
@page_offset = (@page_size -1) * @page_limit


+ 3
- 3
app/controllers/concerns/acceleratorable.rb View File

@@ -18,15 +18,15 @@ module Acceleratorable
end

def accelerator_domain
Gitea.gitea_config[:accelerator]["domain"]
GiteaService.gitea_config[:accelerator]["domain"]
end

def accelerator_username
Gitea.gitea_config[:accelerator]["access_key_id"]
GiteaService.gitea_config[:accelerator]["access_key_id"]
end
def config_accelerator?
Gitea.gitea_config[:accelerator].present?
GiteaService.gitea_config[:accelerator].present?
end
def is_foreign_url?(clone_addr)


+ 20
- 0
app/controllers/concerns/api/project_helper.rb View File

@@ -0,0 +1,20 @@
module Api::ProjectHelper
extend ActiveSupport::Concern

def load_project
namespace = params[:owner]
repo = params[:repo]

@project, @owner = Project.find_with_namespace(namespace, repo)

if @project
logger.info "###########:project founded"
@project
else
logger.info "###########:project not found"
@project = nil
render_not_found and return
end
@project
end
end

+ 19
- 0
app/controllers/concerns/api/user_helper.rb View File

@@ -0,0 +1,19 @@
module Api::UserHelper
extend ActiveSupport::Concern

def load_observe_user
username = params[:owner]

@observe_user = User.find_by(login: username)

if @observe_user
logger.info "###########observe_user not founded"
@observe_user
else
logger.info "###########observe_user not found"
@observe_user = nil
render_not_found and return
end
@observe_user
end
end

+ 1
- 0
app/controllers/concerns/login_helper.rb View File

@@ -116,6 +116,7 @@ module LoginHelper
interactor = Gitea::User::UpdateInteractor.call(user.login, sync_params.merge(hash))
if interactor.success?
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea success _########"
user.update_column(:is_sync_pwd, true)
true
else
Rails.logger.info "########_ login is #{user.login} sync_pwd_to_gitea fail!: #{interactor.error}"


+ 10
- 1
app/controllers/concerns/repository/languages_percentagable.rb View File

@@ -5,7 +5,16 @@ module Repository::LanguagesPercentagable
result = Gitea::Repository::Languages::ListService.call(@owner.login,
@repository.identifier, current_user&.gitea_token)

result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
@transform_language = result[:status] === :success ? hash_transform_precentagable(result[:body]) : nil
update_project_language(@transform_language) unless @transform_language.nil?
@transform_language
end

def update_project_language(language)
db_language = ProjectLanguage.find_or_create_by!(name: language.keys.first.downcase.upcase_first)
@project.update_column(:project_language_id, db_language.id)
rescue
return
end

# hash eq:{"JavaScript": 301681522,"Ruby": 1444004,"Roff": 578781}


+ 39
- 0
app/controllers/oauth2_controller.rb View File

@@ -0,0 +1,39 @@
class Oauth2Controller < ActionController::Base
layout 'doorkeeper/application'
include LoginHelper

def show
client_id = params[:call_url].split("client_id=")[1].split("&redirect_uri")[0]
@call_url = request.fullpath.split('call_url=').last
@app = Doorkeeper::Application.find_by(uid: client_id)
end

def create
if params[:login].blank?
@error = {msg: '邮箱地址或用户名不能为空', id: 'login'}
elsif params[:password].blank?
@error = {msg: '请输入密码', id: 'password'}
else
@user = User.try_to_login(params[:login], params[:password])

return @error = {msg: '账号或密码错误', id: 'login'} if @user.blank?
return @error = {msg: '违反平台使用规范,账号已被锁定', id: 'login'} if @user.locked?

login_control = LimitForbidControl::UserLogin.new(@user)
return @error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'} if login_control.forbid?

password_ok = @user.check_password?(params[:password].to_s)
unless password_ok
if login_control.remain_times-1 == 0
@error = {msg: "登录密码出错已达上限,账号已被锁定, 请#{login_control.forbid_expires/60}分钟后重新登录或找回密码", id: 'account'}
else
@error = {msg: "你已经输错密码#{login_control.error_times+1}次,还剩余#{login_control.remain_times-1}次机会", id: 'account'}
end
login_control.increment!
return
end
login_control.clear
redirect_to params[:call_url] + "&auth=" + @user.login
end
end
end

+ 42
- 0
app/controllers/projects/project_invite_links_controller.rb View File

@@ -0,0 +1,42 @@
class Projects::ProjectInviteLinksController < Projects::BaseController
before_action :require_manager!, except: [:show_link, :redirect_link]
before_action :require_login

def current_link
role = params[:role]
is_apply = params[:is_apply]
return render_error('请输入正确的参数!') unless role.present? && is_apply.present?
@project_invite_link = ProjectInviteLink.find_by(user_id: current_user.id, project_id: @project.id, role: role, is_apply: is_apply)
@project_invite_link = ProjectInviteLink.build!(@project, current_user, role, is_apply) unless @project_invite_link.present?
end

def generate_link
ActiveRecord::Base.transaction do
params_data = link_params.merge({user_id: current_user.id, project_id: @project.id})
Projects::ProjectInviteLinks::CreateForm.new(params_data).validate!
@project_invite_link = ProjectInviteLink.build!(project, user, params_data[:role], params_data[:is_apply])
end
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
end

def show_link
@project_invite_link = ProjectInviteLink.find_by(sign: params[:invite_sign])
return render_not_found unless @project_invite_link.present?
end

def redirect_link
Projects::LinkJoinService.call(current_user, @project, params[:invite_sign])
render_ok
rescue Exception => e
uid_logger_error(e.message)
normal_status(-1, e.message)
end


private
def link_params
params.require(:project_invite_link).permit(:role, :is_apply)
end
end

+ 7
- 1
app/controllers/pull_requests_controller.rb View File

@@ -56,7 +56,12 @@ class PullRequestsController < ApplicationController
end

def create
# return normal_status(-1, "您不是目标分支开发者,没有权限,请联系目标分支作者.") unless @project.operator?(current_user)
if params[:fork_project_id].present?
fork_project= Project.find_by(id: params[:fork_project_id])
return normal_status(-1, "您不是源项目开发者,没有权限,请联系源项目管理员.") unless fork_project && fork_project.operator?(current_user)
else
return normal_status(-1, "您不是项目开发者,没有权限,请联系项目管理员.") unless @project.operator?(current_user)
end
ActiveRecord::Base.transaction do
Issues::CreateForm.new({subject: params[:title], description: params[:body].blank? ? params[:body] : params[:body].b}).validate!
@pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params)
@@ -176,6 +181,7 @@ class PullRequestsController < ApplicationController
@issue_assign_to = @issue.get_assign_user
@gitea_pull = Gitea::PullRequest::GetService.call(@owner.login,
@repository.identifier, @pull_request.gitea_number, current_user&.gitea_token)
@last_review = @pull_request.issue.reviews.take
end

def pr_merge


+ 8
- 8
app/controllers/repositories_controller.rb View File

@@ -9,7 +9,7 @@ class RepositoriesController < ApplicationController
before_action :load_repository
before_action :authorizate!, except: [:sync_mirror, :tags, :commit, :archive]
before_action :authorizate_user_can_edit_repo!, only: %i[sync_mirror]
before_action :get_ref, only: %i[entries sub_entries top_counts file archive]
before_action :get_ref, only: %i[entries sub_entries top_counts files archive]
before_action :get_latest_commit, only: %i[entries sub_entries top_counts]
before_action :get_statistics, only: %i[top_counts]

@@ -54,7 +54,7 @@ class RepositoriesController < ApplicationController
else
@entries = Gitea::Repository::Entries::ListService.new(@owner, @project.identifier, ref: @ref).call
@entries = @entries.present? ? @entries.sort_by{ |hash| hash['type'] } : []
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
end
end

@@ -99,7 +99,7 @@ class RepositoriesController < ApplicationController
end
end
else
@path = Gitea.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
@path = GiteaService.gitea_config[:domain]+"/#{@project.owner.login}/#{@project.identifier}/raw/branch/#{@ref}/"
interactor = Repositories::EntriesInteractor.call(@owner, @project.identifier, file_path_uri, ref: @ref)
if interactor.success?
result = interactor.result
@@ -222,7 +222,7 @@ class RepositoriesController < ApplicationController
else
result = Gitea::Repository::Readme::GetService.call(@owner.login, @repository.identifier, params[:ref], current_user&.gitea_token)
end
@path = Gitea.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
@path = GiteaService.gitea_config[:domain]+"/#{@owner.login}/#{@repository.identifier}/raw/branch/#{params[:ref]}/"
@readme = result[:status] === :success ? result[:body] : nil
@readme['content'] = decode64_content(@readme, @owner, @repository, params[:ref], @path)
@readme['replace_content'] = readme_decode64_content(@readme, @owner, @repository, params[:ref], @path)
@@ -240,8 +240,8 @@ class RepositoriesController < ApplicationController
end

def archive
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
domain = GiteaService.gitea_config[:domain]
api_url = GiteaService.gitea_config[:base_url]
archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{Addressable::URI.escape(params[:archive])}"

file_path = [domain, api_url, archive_url].join
@@ -253,8 +253,8 @@ class RepositoriesController < ApplicationController
end
def raw
domain = Gitea.gitea_config[:domain]
api_url = Gitea.gitea_config[:base_url]
domain = GiteaService.gitea_config[:domain]
api_url = GiteaService.gitea_config[:base_url]

url = "/repos/#{@owner.login}/#{@repository.identifier}/raw/#{Addressable::URI.escape(params[:filepath])}?ref=#{Addressable::URI.escape(params[:ref])}"
file_path = [domain, api_url, url].join


+ 20
- 0
app/controllers/reviews_controller.rb View File

@@ -0,0 +1,20 @@
class ReviewsController < ApplicationController
before_action :require_login
before_action :load_project
before_action :load_pull_request

def create
return render_forbidden('您不是审查人员,无法进行审查!') if current_user&.id != @pull_request.issue.assigned_to_id
@journal, @review = Api::V1::Projects::PullRequests::Reviews::CreateService.call(@project, @pull_request, review_params, current_user)
end

private
def review_params
params.require(:review).permit(:content, :commit_id, :status)
end

def load_pull_request
@pull_request = @project.pull_requests.where(gitea_number: params[:id]).where.not(id: params[:id]).take || PullRequest.find_by_id(params[:id])
end

end

+ 11
- 5
app/controllers/traces/projects_controller.rb View File

@@ -69,12 +69,18 @@ class Traces::ProjectsController < Traces::BaseController


def task_pdf
return render_error("task_id错误") if params[:task_id].blank?
result = Trace::PdfReportService.call(current_user.trace_token, params[:task_id])
if result.is_a?(Hash) && result[:code] == 200
redirect_to result[:download_url]
task_id = params[:task_id]
return render_error("task_id错误") if task_id.blank?
file_save_path = "public/trace_task_results/#{task_id}/report.pdf"
if File.exists?(file_save_path)
redirect_to "/trace_task_results/#{task_id}/report.pdf"
else
render_error("下载报告失败!")
result = Trace::PdfReportService.call(current_user.trace_token, task_id)
if result.is_a?(Hash) && result[:code] == 200
redirect_to result[:download_url]
else
render_error("下载报告失败!")
end
end
rescue Exception => exception
puts exception.message


+ 1
- 1
app/controllers/users_controller.rb View File

@@ -100,7 +100,7 @@ class UsersController < ApplicationController

def get_image
return render_not_found unless @user = User.find_by(login: params[:id]) || User.find_by_id(params[:id])
return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)
# return render_forbidden unless User.current.logged? && (current_user&.admin? || current_user.id == @user.id)

redirect_to Rails.application.config_for(:configuration)['platform_url'] + "/" + url_to_avatar(@user).to_s
end


+ 5
- 5
app/docs/slate/source/api.html.md View File

@@ -1,13 +1,13 @@
---
title: Trustie API Reference
title: GitLink API Reference

language_tabs: # must be one of https://git.io/vQNgJ
- shell: Shell
- javascript: JavaScript

toc_footers:
- <a href='https://www.trustie.net/login?login=false'>Sign Up for a User</a>
- <a href='https://www.trustie.net'>Powered by Trustie</a>
- <a href='https://www.gitlink.org.cn/login'>Sign In for a User</a>
- <a href='https://www.gitlink.org.cn'>Powered by GitLink</a>

includes:
- licenses
@@ -31,8 +31,8 @@ code_clipboard: true

# Introduction

Welcome to the Trustie API! You can use our API to access Trustie API endpoints, which can get information on projects, repository, and users in our platform.
Welcome to the GitLink API! You can use our API to access GitLink API endpoints, which can get information on projects, repository, and users in our platform.

We have language bindings in Shell,avaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.

This example API documentation page was created with [Trustie](https://www.trustie.net). Feel free to edit it and use it as a base for your own API's documentation.
This example API documentation page was created with [GitLink](https://www.gitlink.org.cn). Feel free to edit it and use it as a base for your own API's documentation.

+ 274
- 0
app/docs/slate/source/includes/_projects.md View File

@@ -1,4 +1,278 @@
# Projects
## 获取项目邀请链接(项目管理员)
当前登录(管理员)用户获取项目邀请链接的接口(第一次请求会默认生成role类型为developer和is_apply为true的链接)

> 示例:

```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/current_link.json
```

```javascript
await octokit.request('GET /api/yystopf/kellect/project_invite_links/current_link.json')
```

### HTTP 请求
`GET /api/:owner/:repo/project_invite_links/current_link.json`

### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 |
|is_apply |是| |boolean |是否需要审核 |

### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |

> 返回的JSON示例:

```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```
## 生成项目邀请链接(项目管理员)
当前登录(管理员)用户生成的项目邀请链接,可选role和is_apply参数

> 示例:

```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/generate_link.json
```

```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/generate_link.json')
```

### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/generate_link.json`

### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|role |是| |string |项目权限,reporter: 报告者, developer: 开发者,manager:管理员 |
|is_apply |是| |boolean |是否需要审核 |


> 请求的JSON示例

```json
{
"role": "developer",
"is_apply": false
}
```

### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |

> 返回的JSON示例:

```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```

## 获取邀请链接信息(被邀请用户)
用户请求邀请链接时,通过该接口来获取链接的信息

> 示例:

```shell
curl -X GET http://localhost:3000/api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```

```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/show_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```

### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/show_link.json?invite_sign=xxx`

### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |

### 返回字段说明
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|id |int |链接id |
|role |string |邀请角色|
|is_apply |boolean |是否需要审核 |
|sign |string |邀请标识(放在链接后面即可)|
|expired_at |string |链接过期时间|
|user.id |int |链接创建者的id |
|user.type |string |链接创建者的类型 |
|user.name |string |链接创建者的名称 |
|user.login |string |链接创建者的标识 |
|user.image_url |string |链接创建者头像 |
|project.id |int |链接关联项目的id |
|project.identifier |string |链接关联项目的标识 |
|project.name |string |链接关联项目的名称 |
|project.description |string |链接关联项目的描述 |
|project.is_public |bool |链接关联项目是否公开 |
|project.owner.id |bool |链接关联项目拥有者id |
|project.owner.type |string |链接关联项目拥有者类型 |
|project.owner.name |string |链接关联项目拥有者昵称 |
|project.owner.login |string |链接关联项目拥有者标识 |
|project.owner.image_url|string |链接关联项目拥有者头像 |

> 返回的JSON示例:

```json
{
"id": 7,
"role": "developer",
"is_apply": false,
"sign": "6b6b454843c291d4e52e60853cb8ad9f",
"expired_at": "2022-06-23 10:08",
"user": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"project": {
"id": 474,
"identifier": "kellect",
"name": "kellect",
"description": null,
"is_public": true,
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
}
}
}
```

## 接受项目邀请链接(被邀请用户)
当前登录(非项目)用户加入项目的接口,如果项目链接不需要审核,请求成功后即加入项目,如果需要审核,那么会提交一个申请,需要项目管理员审核

> 示例:

```shell
curl -X POST http://localhost:3000/api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6
```

```javascript
await octokit.request('POST /api/yystopf/kellect/project_invite_links/redirect_link.json?invite_sign=d612df03aad63760445c187bcf83f2e6')
```

### HTTP 请求
`POST /api/:owner/:repo/project_invite_links/redirect_link.json?invite_sign=xxx`

### 请求参数
参数 | 必选 | 默认 | 类型 | 字段说明
--------- | ------- | ------- | -------- | ----------
|invite_sign |是| |string |项目邀请链接的标识 |

> 返回的JSON示例:

```json
{
"status": 0,
"message": "success"
}
```

## 申请加入项目
申请加入项目


+ 1201
- 254
app/docs/slate/source/includes/_repositories.md
File diff suppressed because it is too large
View File


+ 99
- 0
app/docs/slate/source/includes/_users.md View File

@@ -47,6 +47,105 @@ await octokit.request('GET /api/users/me.json')
Success Data.
</aside>

## 用户项目列表
获取用户项目列表

> 示例:

```shell
curl -X GET http://localhost:3000/api/v1/:login/projects.json
```

```javascript
await octokit.request('GET /api/v1/:login/projects.json')
```

### HTTP 请求
`GET api/v1/yystopf/projects.json`

### 请求字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|login | string | 用户的用户名|
|category | string | 归属项目,默认为全部项目, join: 参与项目, created: 创建项目, manage: 管理项目, watched: 关注项目, forked: 复刻项目 |
|is_public | boolean | 公/私有项目,true为公开项目,false为私有项目|
|project_type | string | 项目类型,common为托管项目, mirror为镜像项目, sync_mirror为同步镜像项目|
|sort_by | string | 项目的排序字段,比如 created_on, updated_on等|
|sort_direction | string | 排序的类型,desc 倒序,asc 正序|
|limit | integer | 每页个数 |
|page | integer | 页码 |

### 返回字段说明:
参数 | 类型 | 字段说明
--------- | ----------- | -----------
|total_count | integer | 项目总数 |
|projects.owner.id | integer | 项目拥有者id |
|projects.owner.type | string | 项目拥有者类型,User 用户,Organization 组织 |
|projects.owner.name | string | 项目拥有者名称|
|projects.owner.login | string | 项目拥有者用户名 |
|projects.owner.image_url | string | 项目拥有者头像地址 |
|type | string | 项目类型,common 托管项目,mirror 镜像项目, sync 同步镜像项目 |
|description | string | 项目描述 |
|forked_count | integer | 项目复刻数量 |
|forked_from_project_id | integer | 项目复刻来源项目 |
|identifier | string | 项目标识 |
|issues_count | integer | 项目issues数量|
|pull_requests_count | integer | 项目合并请求数量 |
|invite_code | string | 项目邀请码|
|website | string | 项目网址|
|platform | string | 项目平台 |
|name | string | 项目名称|
|open_devops | boolean | 项目是否开启工作流 |
|praises_count | integer | 项目点赞数量|
|is_public | boolean | 项目是否公开|
|status | integer | 项目状态|
|watchers_count | integer | 项目关注数量|
|ignore_id | integer | 项目ignoreID|
|license_id | integer | 项目许可证ID|
|project_category_id | integer | 项目分类ID|
|project_language_id | integer | 项目语言ID|


> 返回的JSON示例:

```json
"total_count": 1,
"projects": [
{
"owner": {
"id": 2,
"type": "User",
"name": "heh",
"login": "yystopf",
"image_url": "system/lets/letter_avatars/2/H/188_239_142/120.png"
},
"type": "common",
"description": null,
"forked_count": 1,
"forked_from_project_id": null,
"identifier": "hahahah",
"issues_count": 5,
"pull_requests_count": 3,
"invite_code": "8zfKtM",
"website": null,
"platform": "forge",
"name": "hahahah",
"open_devops": false,
"praises_count": 0,
"is_public": true,
"status": 1,
"watchers_count": 0,
"ignore_id": null,
"license_id": null,
"project_category_id": null,
"project_language_id": null
}
]
```
<aside class="success">
Success Data.
</aside>

## 用户消息列表
获取用户消息列表



+ 8
- 0
app/forms/projects/project_invite_links/create_form.rb View File

@@ -0,0 +1,8 @@
class Projects::ProjectInviteLinks::CreateForm < BaseForm
attr_accessor :user_id, :project_id, :role, :is_apply
validates :user_id, :project_id, :role, presence: true
validates :role, inclusion: { in: %w(manager developer reporter), message: "请输入正确的权限." }
validates :is_apply, inclusion: {in: [true, false], message: "请输入是否需要管理员审核."}
end

+ 1
- 1
app/helpers/projects_helper.rb View File

@@ -30,7 +30,7 @@ module ProjectsHelper
end

def gitea_domain
Gitea.gitea_config[:domain]
GiteaService.gitea_config[:domain]
end

def find_user_by_login_or_mail(identifier)


+ 217
- 218
app/helpers/repositories_helper.rb View File

@@ -1,218 +1,217 @@
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
project.get_premission(user)
end
def render_decode64_content(str)
return nil if str.blank?
Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end
def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv)
default_type.include?(str&.downcase) || str.blank?
end
def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase)
end
def is_readme?(type, str)
return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end
def render_commit_author(author_json)
return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
if author_json["id"].present?
return find_user_by_gitea_uid author_json['id']
end
if author_json["id"].nil? && (author_json["name"].present? && author_json["email"].present?)
return find_user_by_login_and_mail(author_json['name'], author_json["email"])
end
end
def render_cache_commit_author(author_json)
if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email'])
end
if author_json["Name"].present? && author_json["Email"].present?
return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
end
end
def readme_render_decode64_content(str, owner, repo, ref, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')
c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
src2_regex = /src='(.*?)'/
ss = content.to_s.scan(c_regex)
ss_src = content.scan(src_regex)
ss_src2 = content.scan(src2_regex)
total_images = ss + ss_src + ss_src2
if total_images.length > 0
total_images.each do |s|
begin
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
# if remove_title.length > 0
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# end
path_last = r_content
path_current = ""
# 相对路径处理
if r_content.start_with?("../")
relative_path_length = r_content.split("../").size - 1
path_pre = path.split("/").size - 1 - relative_path_length
path_pre = 0 if path_pre < 0
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_last = r_content.split("../").last
elsif r_content.start_with?("/") # 根路径处理
path_last = r_content[1..r_content.size]
else
path_current = path
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content
unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# new_r_content = "#{path}" + new_r_content
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
end
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
rescue
next
end
end
end
return content
rescue
return str
end
end
# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if image_type?(ext) || download_type(ext)
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub(s[0], "/#{s_content}")
end
rescue
next
end
end
return content
rescue
return str
end
# unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
end
# date for example: 2020-11-01T19:57:27+08:00
def render_format_time_with_date(date)
date.to_time.strftime("%Y-%m-%d %H:%M")
end
def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end
def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
return Base64.decode64(content).force_encoding('UTF-8')
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)
return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] : entry['content']
end
if download_type(file_type)
return entry['content']
end
render_decode64_content(entry['content'])
end
end
def base64_to_image(path, content)
# generate to https://git.trusite.net/pawm36ozq/-/raw/branch/master/entrn.png"
content = Base64.decode64(content)
File.open(path, 'wb') { |f| f.write(content) }
end
def render_download_image_url(dir_path, file_path, content)
full_path = file_path.starts_with?("/") ? [dir_path, file_path].join("") : [dir_path, file_path].join("/")
file_name = full_path.split("/")[-1]
# 用户名/项目标识/文件路径
dir_path = generate_dir_path(full_path.split("/"+file_name)[0])
file_path = [dir_path, file_name].join('/')
puts "##### render_download_image_url file_path: #{file_path}"
base64_to_image(file_path, content)
file_path = file_path[6..-1]
File.join(base_url, file_path)
end
def generate_dir_path(dir_path)
# tmp_dir_path
# eg: jasder/forgeplus/raw/branch/ref
dir_path = ["public", tmp_dir, dir_path].join('/')
puts "#### dir_path: #{dir_path}"
unless Dir.exists?(dir_path)
FileUtils.mkdir_p(dir_path) ##不成功这里会抛异常
end
dir_path
end
def tmp_dir
"repo"
end
end
module RepositoriesHelper
def render_permission(user, project)
return "Admin" if user&.admin?
project.get_premission(user)
end

def render_decode64_content(str)
return nil if str.blank?
Base64.decode64(str).force_encoding("UTF-8").encode("UTF-8", invalid: :replace)
end

def download_type(str)
default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk)
default_type.include?(str&.downcase) || str.blank?
end

def image_type?(str)
default_type = %w(png jpg gif tif psd svg bmp webp jpeg ico psd)
default_type.include?(str&.downcase)
end

def is_readme?(type, str)
return false if type != 'file' || str.blank?
readme_types = ["readme.md", "readme", "readme_en.md", "readme_zh.md", "readme_en", "readme_zh"]
readme_types.include?(str.to_s.downcase) || str =~ CustomRegexp::MD_REGEX
end

def render_commit_author(author_json)
return nil if author_json.blank? || (author_json["id"].blank? && author_json['name'].blank?)
if author_json["id"].present?
return find_user_by_gitea_uid author_json['id']
end
if author_json["id"].nil? && (author_json["name"].present? && author_json["email"].present?)
return find_user_by_login_and_mail(author_json['name'], author_json["email"])
end
end

def render_cache_commit_author(author_json)
if author_json["name"].present? && author_json["email"].present?
return find_user_in_redis_cache(author_json['name'], author_json['email'])
end
if author_json["Name"].present? && author_json["Email"].present?
return find_user_in_redis_cache(author_json['Name'], author_json['Email'])
end
end

def readme_render_decode64_content(str, owner, repo, ref, path)
return nil if str.blank?
begin
content = Base64.decode64(str).force_encoding('UTF-8')

c_regex = /\!\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
src2_regex = /src='(.*?)'/
ss = content.to_s.scan(c_regex)
ss_src = content.scan(src_regex)
ss_src2 = content.scan(src2_regex)
total_images = ss + ss_src + ss_src2
if total_images.length > 0
total_images.each do |s|
begin
image_title = /\"(.*?)\"/
r_content = s[0]
remove_title = r_content.to_s.scan(image_title)
# if remove_title.length > 0
# r_content = r_content.gsub(/#{remove_title[0]}/, "").strip
# end
path_last = r_content
path_current = ""
# 相对路径处理
if r_content.start_with?("../")
relative_path_length = r_content.split("../").size - 1
path_pre = path.split("/").size - 1 - relative_path_length
path_pre = 0 if path_pre < 0
path_current = path_pre == 0 ? "" : path.split("/")[0..path_pre].join("/")
path_last = r_content.split("../").last
elsif r_content.start_with?("/") # 根路径处理
path_last = r_content[1..r_content.size]
else
path_current = path
end
# if r_content.include?("?")
# new_r_content = r_content + "&raw=true"
# else
# new_r_content = r_content + "?raw=true"
# end
new_r_content = r_content

unless r_content.include?("http://") || r_content.include?("https://") || r_content.include?("mailto:")
# new_r_content = "#{path}" + new_r_content
new_r_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{path_current}/#{path_last}&ref=#{ref}"].join
end
content = content.gsub(/src=\"#{r_content}\"/, "src=\"#{new_r_content}\"").gsub(/src='#{r_content}'/, "src=\"#{new_r_content}\"")
rescue
next
end
end
end
return content
rescue
return str
end
end

# author hui.he
def new_readme_render_decode64_content(str, owner, repo, ref, readme_path, readme_name)
file_path = readme_path.include?('/') ? readme_path.gsub("/#{readme_name}", '') : readme_path.gsub("#{readme_name}", '')
return nil if str.blank?
content = Base64.decode64(str).force_encoding('UTF-8')
s_regex = /\[.*?\]\((.*?)\)/
src_regex = /src=\"(.*?)\"/
ss = content.to_s.scan(s_regex)
ss_src = content.to_s.scan(src_regex)
total_sources = ss + ss_src
total_sources.uniq!
total_sources.each do |s|
begin
s_content = s[0]
# 链接直接跳过不做替换
next if s_content.starts_with?('http://') || s_content.starts_with?('https://') || s_content.starts_with?('mailto:') || s_content.blank?
ext = File.extname(s_content)[1..-1]
if (image_type?(ext) || download_type(ext)) && !ext.blank?
s_content = File.expand_path(s_content, file_path)
s_content = s_content.split("#{Rails.root}/")[1]
# content = content.gsub(s[0], "/#{s_content}")
s_content = [base_url, "/api/#{owner&.login}/#{repo.identifier}/raw?filepath=#{s_content}&ref=#{ref}"].join
content = content.gsub(s[0], s_content)
else
path = [owner&.login, repo&.identifier, 'tree', ref, file_path].join("/")
s_content = File.expand_path(s_content, path)
s_content = s_content.split("#{Rails.root}/")[1]
content = content.gsub('('+s[0]+')', '('+"/#{s_content}"+')')
end
rescue
next
end
end

return content
rescue
return str
end

# unix_time values for example: 1604382982
def render_format_time_with_unix(unix_time)
Time.at(unix_time).strftime("%Y-%m-%d %H:%M")
end

# date for example: 2020-11-01T19:57:27+08:00
def render_format_time_with_date(date)
date.to_time.strftime("%Y-%m-%d %H:%M")
end

def readme_decode64_content(entry, owner, repo, ref, path=nil)
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
new_readme_render_decode64_content(content, owner, repo, ref, entry['path'], entry['name'])
end

def decode64_content(entry, owner, repo, ref, path=nil)
if is_readme?(entry['type'], entry['name'])
Rails.logger.info("entry===#{entry["type"]} #{entry["name"]}")
content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content']
# Rails.logger.info("content===#{content}")
# readme_render_decode64_content(content, owner, repo, ref)
return Base64.decode64(content).force_encoding('UTF-8')
else
file_type = File.extname(entry['name'].to_s)[1..-1]
if image_type?(file_type)
return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, URI.escape(entry['path']), ref: ref)['content'] : entry['content']
end
if download_type(file_type)
return entry['content']
end
render_decode64_content(entry['content'])
end
end

def base64_to_image(path, content)
# generate to https://git.trusite.net/pawm36ozq/-/raw/branch/master/entrn.png"
content = Base64.decode64(content)
File.open(path, 'wb') { |f| f.write(content) }
end
def render_download_image_url(dir_path, file_path, content)
full_path = file_path.starts_with?("/") ? [dir_path, file_path].join("") : [dir_path, file_path].join("/")
file_name = full_path.split("/")[-1]
# 用户名/项目标识/文件路径
dir_path = generate_dir_path(full_path.split("/"+file_name)[0])

file_path = [dir_path, file_name].join('/')

puts "##### render_download_image_url file_path: #{file_path}"
base64_to_image(file_path, content)
file_path = file_path[6..-1]
File.join(base_url, file_path)
end
def generate_dir_path(dir_path)
# tmp_dir_path
# eg: jasder/forgeplus/raw/branch/ref
dir_path = ["public", tmp_dir, dir_path].join('/')
puts "#### dir_path: #{dir_path}"
unless Dir.exists?(dir_path)
FileUtils.mkdir_p(dir_path) ##不成功这里会抛异常
end
dir_path
end

def tmp_dir
"repo"
end
end

+ 2
- 2
app/interactors/gitea/register_interactor.rb View File

@@ -44,8 +44,8 @@ module Gitea

def token
{
username: Gitea.gitea_config[:access_key_id],
password: Gitea.gitea_config[:access_key_secret]
username: GiteaService.gitea_config[:access_key_id],
password: GiteaService.gitea_config[:access_key_secret]
}
end
end


+ 1
- 1
app/libs/ci/drone/server.rb View File

@@ -37,7 +37,7 @@ class Ci::Drone::Server

private
def gitea_url
Gitea.gitea_config[:domain]
GiteaService.gitea_config[:domain]
end

def database_username


app/libs/gitea.rb → app/libs/gitea_service.rb View File

@@ -1,4 +1,4 @@
module Gitea
module GiteaService
class << self
def gitea_config
gitea_config = {}

+ 12
- 9
app/models/applied_project.rb View File

@@ -2,24 +2,27 @@
#
# Table name: forge_applied_projects
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("0")
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
# project_invite_link_id :integer
#
# Indexes
#
# index_forge_applied_projects_on_project_id (project_id)
# index_forge_applied_projects_on_user_id (user_id)
# index_forge_applied_projects_on_project_id (project_id)
# index_forge_applied_projects_on_project_invite_link_id (project_invite_link_id)
# index_forge_applied_projects_on_user_id (user_id)
#

class AppliedProject < ApplicationRecord
self.table_name = "forge_applied_projects"
belongs_to :user
belongs_to :project
belongs_to :project_invite_link, optional: true

has_many :applied_messages, as: :applied, dependent: :destroy
# has_many :forge_activities, as: :forge_act, dependent: :destroy


+ 6
- 0
app/models/commit_log.rb View File

@@ -0,0 +1,6 @@
class CommitLog < ApplicationRecord
belongs_to :user
belongs_to :project
belongs_to :repository

end

+ 1
- 0
app/models/issue.rb View File

@@ -69,6 +69,7 @@ class Issue < ApplicationRecord
has_many :issue_tags, through: :issue_tags_relates
has_many :issue_times, dependent: :destroy
has_many :issue_depends, dependent: :destroy
has_many :reviews, dependent: :destroy
scope :issue_includes, ->{includes(:user)}
scope :issue_many_includes, ->{includes(journals: :user)}
scope :issue_issue, ->{where(issue_classify: [nil,"issue"])}


+ 2
- 0
app/models/journal.rb View File

@@ -12,11 +12,13 @@
# parent_id :integer
# comments_count :integer default("0")
# reply_id :integer
# review_id :integer
#
# Indexes
#
# index_journals_on_created_on (created_on)
# index_journals_on_journalized_id (journalized_id)
# index_journals_on_review_id (review_id)
# index_journals_on_user_id (user_id)
# journals_journalized_id (journalized_id,journalized_type)
#


+ 1
- 0
app/models/message_template/custom_tip.rb View File

@@ -61,6 +61,7 @@ class MessageTemplate::CustomTip < MessageTemplate
end
title.gsub!('{platform}', PLATFORM)
content.gsub!('{platform}', PLATFORM)
content.gsub!('{baseurl}', base_url)

return title, content
rescue => e


+ 4
- 3
app/models/project.rb View File

@@ -125,6 +125,7 @@ class Project < ApplicationRecord
has_many :has_pinned_users, through: :pinned_projects, source: :user
has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id
has_many :user_trace_tasks, dependent: :destroy
has_many :project_invite_links, dependent: :destroy
after_create :incre_user_statistic, :incre_platform_statistic
after_save :check_project_members
before_save :set_invite_code, :reset_unmember_followed, :set_recommend_and_is_pinned, :reset_cache_data
@@ -138,7 +139,7 @@ class Project < ApplicationRecord
delegate :content, to: :project_detail, allow_nil: true
delegate :name, to: :license, prefix: true, allow_nil: true

validate :validate_sensitive_string
validate :validate_sensitive_string, on: [:create, :update]

def self.all_visible(user_id=nil)
user_projects_sql = Project.joins(:owner).where(users: {type: 'User'}).to_sql
@@ -184,7 +185,7 @@ class Project < ApplicationRecord
forked_project = self.forked_from_project
if forked_project.present?
forked_project.decrement(:forked_count, 1)
forked_project.save
forked_project.update_column(:forked_count, forked_project.forked_count)
end
end

@@ -373,7 +374,7 @@ class Project < ApplicationRecord
logger.info "########namespace_path: #{namespace_path} ########identifier: #{identifier} "

user = Owner.find_by_login namespace_path
user = Owner.new(login: namespace_path) if user.nil?
user = User.new(login: namespace_path) if user.nil?
project = user&.projects&.find_by(identifier: identifier) || Project.find_by(identifier: "#{namespace_path}/#{identifier}")
return nil if project.blank?



+ 59
- 0
app/models/project_invite_link.rb View File

@@ -0,0 +1,59 @@
# == Schema Information
#
# Table name: project_invite_links
#
# id :integer not null, primary key
# project_id :integer
# user_id :integer
# role :integer default("4")
# is_apply :boolean default("1")
# sign :string(255)
# expired_at :datetime
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_project_invite_links_on_project_id (project_id)
# index_project_invite_links_on_sign (sign)
# index_project_invite_links_on_user_id (user_id)
#

class ProjectInviteLink < ApplicationRecord

default_scope { where("expired_at > ?", Time.now).or(where(expired_at: nil)) }

belongs_to :project
belongs_to :user
has_many :applied_projects

scope :with_project_id, -> (project_id) {where(project_id: project_id)}
scope :with_user_id, -> (user_id) {where(user_id: user_id)}

enum role: {manager: 3, developer: 4, reporter: 5}

before_create :set_old_data_expired_at

def self.random_hex_sign
hex = (SecureRandom.hex(32))
return hex unless ProjectInviteLink.where(sign: hex).exists?
end

def self.build!(project, user, role="developer", is_apply=true)
self.create!(
project_id: project&.id,
user_id: user&.id,
role: role,
is_apply: is_apply,
sign: random_hex_sign,
expired_at: Time.now + 3.days
)
end

private
def set_old_data_expired_at
ProjectInviteLink.where(user_id: self.user_id, project_id: self.project, role: self.role, is_apply: self.is_apply).update_all(expired_at: Time.now)
end


end

+ 1
- 0
app/models/project_unit.rb View File

@@ -14,6 +14,7 @@
#

class ProjectUnit < ApplicationRecord

belongs_to :project

enum unit_type: {code: 1, issues: 2, pulls: 3, wiki:4, devops: 5, versions: 6, resources: 7, services: 8}


+ 27
- 0
app/models/review.rb View File

@@ -0,0 +1,27 @@
# == Schema Information
#
# Table name: reviews
#
# id :integer not null, primary key
# issue_id :integer
# reviewer_id :integer
# content :text(65535)
# commit_id :string(255)
# status :integer default("0")
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_reviews_on_issue_id (issue_id)
# index_reviews_on_reviewer_id (reviewer_id)
#

class Review < ApplicationRecord

belongs_to :issue
belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id
has_one :journal, dependent: :destroy

enum status: {common: 0, approved: 1, rejected: 2}
end

+ 18
- 2
app/models/user.rb View File

@@ -181,7 +181,7 @@ class User < Owner
scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) }
scope :like, lambda { |keywords|
sql = "CONCAT(lastname, firstname) LIKE :search OR nickname LIKE :search OR login LIKE :search OR mail LIKE :search OR nickname LIKE :search"
where(sql, :search => "%#{keywords.split(" ").join('|')}%") unless keywords.blank?
where(sql, :search => "%#{keywords.strip}%") unless keywords.blank?
}

scope :simple_select, -> {select(:id, :login, :lastname,:firstname, :nickname, :gitea_uid, :type)}
@@ -567,7 +567,8 @@ class User < Owner
return '游客' unless logged?
name = lastname + firstname
name = name.blank? ? (nickname.blank? ? login : nickname) : name
name.gsub(/\s+/, '').strip #6.11 -hs
# name.gsub(/\s+/, '').strip #6.11 -hs
name.strip
end

def only_real_name
@@ -684,6 +685,21 @@ class User < Owner
raise text
end

def self.authenticate!(login, password)
user = self.where("login = ? or mail = ? or phone = ? ", login.to_s.gsub(" ",''),login.to_s.gsub(" ",''),login.downcase.to_s.gsub(" ",'')).limit(1).first
return (user.check_password?(password) ? user : nil) unless user.nil?
nil
end

# Generate public/private keys
def generate_keys
key_size = (Rails.env == 'test' ? 512 : 2048)

serialized_private_key = OpenSSL::PKey::RSA::generate(key_size).to_s
serialized_public_key = OpenSSL::PKey::RSA.new(serialized_private_key)
[serialized_private_key, serialized_public_key]
end

def show_real_name
name = lastname + firstname
if name.blank?


+ 38
- 0
app/services/api/v1/projects/blame_service.rb View File

@@ -0,0 +1,38 @@
class Api::V1::Projects::BlameService < ApplicationService
include ActiveModel::Model

attr_reader :project, :sha, :filepath, :owner, :repo, :token
attr_accessor :gitea_data

validates :sha, :filepath, presence: true

def initialize(project, sha, filepath, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@sha = sha
@filepath = filepath
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?
load_gitea_data

gitea_data
end

private
def request_params
{
access_token: token,
sha: sha,
filepath: filepath
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_blame_by_owner_repo(owner, repo, {query: request_params})
raise Error, '获取项目blame失败!' unless @gitea_data.is_a?(Hash)
end
end

+ 30
- 0
app/services/api/v1/projects/branches/all_list_service.rb View File

@@ -0,0 +1,30 @@
class Api::V1::Projects::Branches::AllListService < ApplicationService

attr_accessor :project, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
load_gitea_data
gitea_data
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil
raise Error, '获取所有分支失败!' unless @gitea_data.is_a?(Hash)
end
end

+ 51
- 0
app/services/api/v1/projects/branches/create_service.rb View File

@@ -0,0 +1,51 @@
class Api::V1::Projects::Branches::CreateService < ApplicationService
include ActiveModel::Model

attr_accessor :project, :token, :owner, :repo, :old_branch_name, :new_branch_name
attr_accessor :gitea_data

validates :new_branch_name, :old_branch_name, presence: true

def initialize(project, params, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@new_branch_name = params[:new_branch_name]
@old_branch_name = params[:old_branch_name]
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?

check_new_branch_exist
excute_data_to_gitea
gitea_data
end

private
def request_params
{
access_token: token
}
end

def request_body
{
new_branch_name: new_branch_name,
old_branch_name: old_branch_name,
}
end

def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_branches_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
raise Error, '创建分支失败!' unless @gitea_data.is_a?(Hash)
end

def check_new_branch_exist
result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params}) rescue nil
raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
raise Error, '分支已存在!' if result['branch_name'].include?(@new_branch_name)
end
end

+ 36
- 0
app/services/api/v1/projects/commits/diff_service.rb View File

@@ -0,0 +1,36 @@
class Api::V1::Projects::Commits::DiffService < ApplicationService
include ActiveModel::Model

attr_accessor :project, :sha, :token, :owner, :repo
attr_accessor :gitea_data

validates :sha, presence: true

def initialize(project, sha, token = nil)
@project = project
@sha = sha
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?
load_gitea_data

gitea_data
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_commits_diff_by_owner_repo_sha(owner, repo, sha, {query: request_params}) rescue nil
raise Error, '获取提交对比失败!' unless @gitea_data.is_a?(Hash)
end

end

+ 38
- 0
app/services/api/v1/projects/commits/list_service.rb View File

@@ -0,0 +1,38 @@
class Api::V1::Projects::Commits::ListService < ApplicationService

attr_reader :project, :sha, :page, :limit, :owner, :repo, :token
attr_accessor :gitea_data

def initialize(project, params, token=nil)
@project = project
@sha = params[:sha]
@page = params[:page] || 1
@limit = params[:limit] || 15
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
load_gitea_data

gitea_data
end

private
def request_params
param = {
access_token: token,
page: page,
limit: limit
}
param.merge!(sha: sha) if sha.present?

param
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_commits_by_owner_repo(owner, repo, {query: request_params}) rescue nil
raise Error, '获取提交列表失败!' unless @gitea_data.is_a?(Hash)
end
end

+ 34
- 0
app/services/api/v1/projects/compare_service.rb View File

@@ -0,0 +1,34 @@
class Api::V1::Projects::CompareService < ApplicationService
include ActiveModel::Model
attr_reader :project, :from, :to, :token, :owner, :repo
attr_accessor :gitea_data

validates :from, :to, presence: true

def initialize(project, from, to, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@from = from
@to = to
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?
load_gitea_data
raise Error, '获取对比信息失败!' unless gitea_data.is_a?(Hash)
gitea_data
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_compare_by_owner_repo_from_to(owner, repo, from, to, {query: request_params}) rescue nil
end
end

+ 91
- 0
app/services/api/v1/projects/contents/batch_create_service.rb View File

@@ -0,0 +1,91 @@
class Api::V1::Projects::Contents::BatchCreateService < ApplicationService
include ActiveModel::Model

attr_reader :project, :owner, :repo, :token
attr_reader :files, :author_email, :author_name, :author_timeunix, :branch, :committer_email, :committer_name, :committer_timeunix, :message, :new_branch
attr_accessor :gitea_data

validates :author_email, :committer_email, presence: true, format: { with: CustomRegexp::EMAIL }
validates :author_name, :committer_name, presence: true, format: { with: /\A(?!_)(?!.*?_$)[a-zA-Z0-9_-]{4,15}\z/ }
validates :author_timeunix, :committer_timeunix, presence: true
validates :branch, presence: true
validates :message, presence: true


def initialize(project, params, token=nil)
puts params
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
@files = params[:files]
@author_email = params[:author_email]
@author_name = params[:author_name]
@author_timeunix = params[:author_timeunix]
@branch = params[:branch]
@committer_email = params[:committer_email]
@committer_name = params[:committer_name]
@committer_timeunix = params[:committer_timeunix]
@message = params[:message]
@new_branch = params[:new_branch]
end

def call
raise Error, '请输入正确的文件参数Files' unless valid_files?
raise Error, errors.full_messages.join(", ") unless valid?
check_branch_exist
excute_data_to_gitea

gitea_data
end

private
def request_params
{
access_token: token
}
end
def request_body
{
files: files,
header: {
author: {
email: author_email,
name: author_name
},
committer: {
email: committer_email,
name: committer_name
},
dates: {
author: Time.at(author_timeunix.to_i),
committer: Time.at(committer_timeunix.to_i)
},
message: message,
new_branch: new_branch,
signoff: false
}
}
end

def valid_files?
return false unless files.is_a?(Array) && !files.blank?
files.each do |file|
return false unless file.has_key?(:action_type) && file.has_key?(:content) && file.has_key?(:encoding) && file.has_key?(:file_path)
end
end

def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_contents_batch_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
raise Error, '创建文件失败!' unless @gitea_data.is_a?(Hash)
end

def check_branch_exist
result = $gitea_client.get_repos_branch_name_set_by_owner_repo(owner, repo, {query: request_params} ) rescue nil
raise Error, '查询分支名称失败!' unless result.is_a?(Hash)
raise Error, '分支不存在!' unless result['branch_name'].include?(branch)
raise Error, '分支已存在!' if result['branch_name'].include?(new_branch) && new_branch.nil?
end

end

+ 50
- 0
app/services/api/v1/projects/get_service.rb View File

@@ -0,0 +1,50 @@
class Api::V1::Projects::GetService < ApplicationService

attr_reader :project, :token, :owner, :repo
attr_accessor :gitea_data, :gitea_branch_tag_count

def initialize(project, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
load_gitea_data
load_gitea_branch_tag_count

result_object
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def result_object
{
full_name: "#{owner}/#{repo}",
owner: project&.owner,
ssh_url: gitea_data["ssh_url"],
clone_url: gitea_data["clone_url"],
size: gitea_data["size"],
default_branch: gitea_data["default_branch"],
empty: gitea_data["empty"],
branch_count: gitea_branch_tag_count["branch_count"],
tag_count: gitea_branch_tag_count["tag_count"],
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_by_owner_repo(owner, repo, {query: request_params}) rescue nil
end

def load_gitea_branch_tag_count
@gitea_branch_tag_count = $gitea_client.get_repos_branch_tag_count_by_owner_repo(owner, repo, {query: request_params}) rescue nil
end
end

+ 34
- 0
app/services/api/v1/projects/git/blobs_service.rb View File

@@ -0,0 +1,34 @@
class Api::V1::Projects::Git::BlobsService < ApplicationService
include ActiveModel::Model

attr_accessor :project, :sha, :token, :owner, :repo
attr_accessor :gitea_data

validates :sha, presence: :true


def initialize(project, sha, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@sha = sha
@token = token
end

def call
load_gitea_data

gitea_data
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_git_blobs_by_owner_repo_sha(owner, repo, sha, {query: request_params}) rescue nil
end
end

+ 52
- 0
app/services/api/v1/projects/git/trees_service.rb View File

@@ -0,0 +1,52 @@
class Api::V1::Projects::Git::TreesService < ApplicationService
include ActiveModel::Model

attr_accessor :project, :token, :sha, :recursive, :page, :limit, :owner, :repo
attr_accessor :gitea_data
validates :sha, presence: :true
validates :recursive, inclusion: {in: [nil, '', true, false]}

def initialize(project, sha, params, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
@sha = sha
@recursive = params[:recursive]
@page = params[:page] || 1
@limit = params[:limit] || 15
end

def call
raise Error, errors.full_messages.join(", ") unless valid?
$gitea_client.token = token unless token.blank?
load_gitea_data

$gitea_client.token = nil unless token.blank?
gitea_data
end

private
def request_query
if recursive.present?
{
recursive: recursive,
page: page,
per_page: limit,
access_token: token
}
else
{
page: page,
per_page: limit,
access_token: token
}
end
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_git_trees_by_owner_repo_sha(owner, repo, sha, {query: request_query}) rescue nil
raise Error, '获取文件树列表失败!' unless @gitea_data.is_a?(Hash)
end
end

+ 40
- 0
app/services/api/v1/projects/pull_requests/reviews/create_service.rb View File

@@ -0,0 +1,40 @@
class Api::V1::Projects::PullRequests::Reviews::CreateService < ApplicationService
include ActiveModel::Model

attr_reader :project, :pull_request, :issue, :status, :commit_id, :content, :current_user
attr_accessor :review, :journal

validates :status, inclusion: { in: %w(common approved rejected), message: '请输入正确的Type'}

def initialize(project, pull_request, params, current_user)
@project = project
@pull_request = pull_request
@issue = pull_request&.issue
@status = params[:status]
@commit_id = params[:commit_id]
@content = params[:content]
@current_user = current_user
end

def call
raise Error, errors.full_messages.join(", ") unless valid?
ActiveRecord::Base.transaction do
create_review
create_journal
end

return @journal, @review
rescue
raise Error, '服务器错误,请联系系统管理员!'
end

private
def create_review
@review = issue.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id)
end

def create_journal
@journal = issue.journals.create!(notes: content, user_id: @current_user.id, review_id: @review.id)
end

end

+ 62
- 0
app/services/api/v1/projects/webhooks/create_service.rb View File

@@ -0,0 +1,62 @@
class Api::V1::Projects::Webhooks::CreateService < ApplicationService
include ActiveModel::Model

attr_reader :project, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events
attr_accessor :gitea_data

validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
validates :active, inclusion: {in: [true, false]}
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}

def initialize(project, params, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@active = params[:active]
@branch_filter = params[:branch_filter]
@content_type = params[:content_type]
@url = params[:url]
@http_method = params[:http_method]
@secret = params[:secret]
@events = params[:events]
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?
begin
excute_data_to_gitea

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end

private
def request_params
{
access_token: token
}
end

def request_body
{
active: active,
branch_filter: branch_filter,
config: {
content_type: content_type,
url: url,
http_method: http_method,
secret: secret
},
events: events || [],
type: 'gitea',
}
end

def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_hooks_by_owner_repo(owner, repo, {body: request_body.to_json, query: request_params}) rescue nil
end
end

+ 32
- 0
app/services/api/v1/projects/webhooks/delete_service.rb View File

@@ -0,0 +1,32 @@
class Api::V1::Projects::Webhooks::DeleteService < ApplicationService

attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
excute_data_to_gitea

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def excute_data_to_gitea
@gitea_data = $gitea_client.delete_repos_hooks_by_owner_repo_id(owner, repo, id, {query: request_params}) rescue nil
end
end

+ 33
- 0
app/services/api/v1/projects/webhooks/get_service.rb View File

@@ -0,0 +1,33 @@
class Api::V1::Projects::Webhooks::GetService < ApplicationService

attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
load_gitea_data


gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_by_owner_repo_id(owner, repo, id, {query: request_params}) rescue nil
end
end

+ 35
- 0
app/services/api/v1/projects/webhooks/hooktasks_service.rb View File

@@ -0,0 +1,35 @@
class Api::V1::Projects::Webhooks::ListService < ApplicationService

attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
$gitea_client.token = token unless token.blank?
load_gitea_data

$gitea_client.token = nil unless token.blank?

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_hooktasks_by_owner_repo(owner, repo, id, {query: request_params}) rescue nil
end
end

+ 31
- 0
app/services/api/v1/projects/webhooks/list_service.rb View File

@@ -0,0 +1,31 @@
class Api::V1::Projects::Webhooks::ListService < ApplicationService

attr_reader :project, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, token=nil)
@project = project
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
load_gitea_data

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def load_gitea_data
@gitea_data = $gitea_client.get_repos_hooks_by_owner_repo(owner, repo, {query: request_params}) rescue nil
end
end

+ 32
- 0
app/services/api/v1/projects/webhooks/tests_service.rb View File

@@ -0,0 +1,32 @@
class Api::V1::Projects::Webhooks::TestsService < ApplicationService

attr_reader :project, :id, :token, :owner, :repo
attr_accessor :gitea_data

def initialize(project, id, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@token = token
end

def call
excute_data_to_gitea

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end

private
def request_params
{
access_token: token
}
end

def excute_data_to_gitea
@gitea_data = $gitea_client.post_repos_hooks_tests_by_owner_repo_id(owner, repo, id, {query: request_params}) rescue nil
end
end

+ 63
- 0
app/services/api/v1/projects/webhooks/update_service.rb View File

@@ -0,0 +1,63 @@
class Api::V1::Projects::Webhooks::UpdateService < ApplicationService
include ActiveModel::Model

attr_reader :project, :id, :token, :owner, :repo, :active, :branch_filter, :content_type, :url, :http_method, :secret, :events
attr_accessor :gitea_data

validates :url, format: { with: URI::regexp(%w[http https]), message: "请输入正确的地址" }
validates :active, inclusion: {in: [true, false]}
validates :http_method, inclusion: { in: %w(POST GET), message: "请输入正确的请求方式"}
validates :content_type, inclusion: { in: %w(json form), message: "请输入正确的Content Type"}

def initialize(project, id, params, token=nil)
@project = project
@id = id
@owner = project&.owner.login
@repo = project&.identifier
@active = params[:active]
@branch_filter = params[:branch_filter]
@content_type = params[:content_type]
@url = params[:url]
@http_method = params[:http_method]
@secret = params[:secret]
@events = params[:events]
@token = token
end

def call
raise Error, errors.full_messages.join(",") unless valid?
begin
excute_data_to_gitea

gitea_data
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end

private
def request_params
{
access_token: token
}
end

def request_body
{
active: active,
branch_filter: branch_filter,
config: {
content_type: content_type,
url: url,
http_method: http_method,
secret: secret
},
events: events || [],
type: 'gitea',
}
end

def excute_data_to_gitea
@gitea_data = $gitea_client.patch_repos_hooks_by_owner_repo_id(owner, repo, id, {body: request_body.to_json, query: request_params}) rescue nil
end
end

+ 86
- 0
app/services/api/v1/users/projects/list_service.rb View File

@@ -0,0 +1,86 @@
class Api::V1::Users::Projects::ListService < ApplicationService
include ActiveModel::Model

attr_reader :observe_user, :category, :is_public, :project_type, :sort_by, :sort_direction, :search, :current_user
attr_accessor :queried_projects

validates :category, inclusion: {in: %w(all join created manage watched forked), message: "请输入正确的Category"}
validates :is_public, inclusion: {in: [true, false], message: '请输入正确的IsPublic'}, allow_nil: true
validates :project_type, inclusion: {in: %w(common mirror sync_mirror), message: '请输入正确的ProjectType'}, allow_nil: true
validates :sort_by, inclusion: {in: Project.column_names, message: '请输入正确的SortBy'}
validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'}

def initialize(observe_user, params, current_user=nil)
@observe_user = observe_user
@category = params[:category] || 'all'
@is_public = params[:is_public]
@project_type = params[:project_type]
@sort_by = params[:sort_by] || 'updated_on'
@sort_direction = params[:sort_direction] || 'desc'
@search = params[:search]
@current_user = current_user
end

def call
raise Error, errors.full_messages.join(", ") unless valid?
begin
project_query_data

queried_projects
rescue
raise Error, "服务器错误,请联系系统管理员!"
end
end

private
def project_query_data
if current_user.admin?
projects = Project
else
projects = Project.visible
end

case category
when 'join'
normal_projects = projects.where.not(user_id: observe_user.id).members_projects(observe_user.id).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}).to_sql
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
when 'created'
projects = projects.where(user_id: observe_user.id)
when 'manage'
normal_projects = projects.joins(members: :roles).where(members: {user_id: observe_user.id}, roles: {name: 'Manager'}).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}, teams: {authorize: %w(owner admin)}).to_sql
projects = Project.from("( #{normal_projects} UNION #{org_projects} ) AS projects").distinct
when 'watched'
projects = projects.where.not(user_id: observe_user.id).joins(:watchers).where(watchers: {watchable_type: "Project", user_id: observe_user.id})
when 'forked'
fork_ids = observe_user.fork_users.select(:id, :fork_project_id).pluck(:fork_project_id)
projects = projects.where(id: fork_ids)
else
normal_projects = projects.members_projects(observe_user.id).to_sql
org_projects = projects.joins(team_projects: [team: :team_users]).where(team_users: {user_id: observe_user.id}).to_sql
projects = Project.from("( #{ normal_projects} UNION #{ org_projects } ) AS projects").distinct
end

unless is_public.nil?
if is_public
projects = projects.visible
else
projects = projects.is_private
end
end

projects = projects.with_project_type(project_type)

q = projects.ransack(name_or_identifier_cont: search)

scope = q.result.includes(:project_category, :project_language,:owner, :repository, :has_pinned_users)


scope = scope.order("projects.#{sort_by} #{sort_direction}")

@queried_projects = scope
end

end

+ 1
- 1
app/services/educoder/client_service.rb View File

@@ -81,7 +81,7 @@ class Educoder::ClientService < ApplicationService
end

def access_key_secret
Gitea.gitea_config[:access_key_secret]
GiteaService.gitea_config[:access_key_secret]
end

def api_url(url)


+ 1
- 1
app/services/gitea/accelerator/base_service.rb View File

@@ -56,7 +56,7 @@ class Gitea::Accelerator::BaseService < ApplicationService
end

def accelerator
Gitea.gitea_config[:accelerator]
GiteaService.gitea_config[:accelerator]
end

def render_status(response)


+ 2
- 2
app/services/gitea/client_service.rb View File

@@ -96,11 +96,11 @@ class Gitea::ClientService < ApplicationService
end

def base_url
Gitea.gitea_config[:base_url]
GiteaService.gitea_config[:base_url]
end

def domain
Gitea.gitea_config[:domain]
GiteaService.gitea_config[:domain]
end

def api_url


+ 2
- 2
app/services/gitea/user/delete_service.rb View File

@@ -14,8 +14,8 @@ class Gitea::User::DeleteService < Gitea::ClientService
private
def token
{
username: Gitea.gitea_config[:access_key_id],
password: Gitea.gitea_config[:access_key_secret]
username: GiteaService.gitea_config[:access_key_id],
password: GiteaService.gitea_config[:access_key_secret]
}
end



+ 1
- 1
app/services/gitea/user/update_service.rb View File

@@ -17,7 +17,7 @@ class Gitea::User::UpdateService < Gitea::ClientService
# source_id integer($int64)
# website string

def initialize(edit_username, params={}, token={username: Gitea.gitea_config[:access_key_id], password: Gitea.gitea_config[:access_key_secret]})
def initialize(edit_username, params={}, token={username: GiteaService.gitea_config[:access_key_id], password: GiteaService.gitea_config[:access_key_secret]})
@token = token
@params = params
@edit_username = edit_username


+ 86
- 0
app/services/projects/link_join_service.rb View File

@@ -0,0 +1,86 @@
class Projects::LinkJoinService < ApplicationService
Error = Class.new(StandardError)

attr_reader :user, :project, :invite_sign, :params

def initialize(user, project, invite_sign, params={})
@user = user
@project = project
@invite_sign = invite_sign
@params = params
end

def call
ActiveRecord::Base.transaction do
validate!
if invite_link.is_apply
# 如果需要申请才能加入,创建一条申请记录
create_applied_project!
else
# 如果不需要申请,直接为项目添加该成员
create_member!
end
end
end

private
def validate!
raise Error, 'invite_sign必须存在!' if invite_sign.blank?
raise Error, '邀请链接不存在!' unless invite_link.present?
raise Error, '邀请链接已失效!' unless invite_user_in_project
raise Error, '您已是仓库成员' if project.member?(user.id)
raise Error, '您的申请管理员正在审核中,请勿重复申请!' if user.applied_projects.exists?(applied_project_params)
end

def applied_project_params
{
status: 'common',
project: project,
role: role_value,
project_invite_link_id: invite_link&.id
}
end

def create_applied_project!
user.applied_projects.find_or_create_by!(status: 'common', project: project, role: role_value, project_invite_link_id: invite_link&.id)
end

def create_member!
Projects::AddMemberInteractor.call(project.owner, project, user, permission)
end

def invite_link
ProjectInviteLink.find_by(project_id: project.id, sign: invite_sign)
end

def invite_user_in_project
in_project = project.member?(invite_link.user)
invite_link.update_column(:expired_at, Time.now) unless in_project
in_project
end

def role_value
@_role ||=
case invite_link&.role
when 'manager' then 3
when 'developer' then 4
when 'reporter' then 5
else
5
end
end

def permission
case invite_link&.role
when 'manager'
'admin'
when 'developer'
'write'
when 'reporter'
'read'
else
'read'
end
end

end

+ 1
- 1
app/services/repositories/create_service.rb View File

@@ -63,7 +63,7 @@ class Repositories::CreateService < ApplicationService
end

def remote_repository_url
[Gitea.gitea_config[:domain], '/', user.login, '/', params[:identifier], ".git"].join("")
[GiteaService.gitea_config[:domain], '/', user.login, '/', params[:identifier], ".git"].join("")
end

def repository_params


+ 12
- 3
app/services/trace/pdf_report_service.rb View File

@@ -1,6 +1,7 @@
# 代码溯源 导出pdf
require 'open-uri'
require 'fileutils'
require 'zip'

class Trace::PdfReportService < Trace::ClientService
@@ -15,8 +16,16 @@ class Trace::PdfReportService < Trace::ClientService
content = open("#{domain}#{base_url}#{url}?task_id=#{task_id}", "Authorization" => token)
if content.is_a?(Tempfile)
check_file_path
IO.copy_stream(content, "#{save_path}/#{task_id}.pdf")
return {code: 200, download_url: "/trace_task_results/#{task_id}.pdf"}
IO.copy_stream(content, "#{save_path}/report.zip")
Zip::File.open("#{save_path}/report.zip") do |zip_file|
zip_file.each do |f|
name = f.name.force_encoding('utf-8')
next unless name == '/report.pdf'
fpath = File.join(save_path, name)
zip_file.extract(f, fpath)
end
end
return {code: 200, download_url: "/trace_task_results/#{task_id}/report.pdf"}
else
return {code: 404}
end
@@ -28,7 +37,7 @@ class Trace::PdfReportService < Trace::ClientService
end

def save_path
"public/trace_task_results"
"public/trace_task_results/#{task_id}"
end

def url


+ 53
- 213
app/views/admins/dashboards/index.html.erb View File

@@ -2,217 +2,57 @@
<% add_admin_breadcrumb('概览', admins_path) %>
<% end %>

<div class="header bg-gradient-primary pb-8 pt-md-8">
<div class="container-fluid">
<div class="header-body">
<!-- Card stats -->
<div class="row">
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">当日活跃用户</h5>
<span class="h2 font-weight-bold mb-0"><%= @active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-success mr-2"><i class="fa fa-arrow-up"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last month</span>-->
<!-- </p>-->
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">7天内活跃用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @weekly_active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-danger mr-2"><i class="fas fa-arrow-down"></i> 3.48%</span>-->
<!-- <span class="text-nowrap">Since last week</span>-->
<!-- </p>-->
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">30天内活跃用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @month_active_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-users"></i>
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-warning mr-2"><i class="fas fa-arrow-down"></i> 1.10%</span>-->
<!-- <span class="text-nowrap">Since yesterday</span>-->
<!-- </p>-->
</div>
</div>
</div>
<div class="col-xl-3 col-lg-6">
<div class="card card-stats mb-4 mb-xl-0">
<div class="card-body">
<div class="row">
<div class="col">
<h5 class="card-title text-uppercase text-muted mb-0">30天内新增用户数</h5>
<span class="h2 font-weight-bold mb-0"><%= @new_user_count %></span>
</div>
<div class="col-auto">
<div class="icon icon-shape rounded-circle shadow">
<i class="fa fa-user-plus"></i>
</div>
</div>
</div>
<!-- <p class="mt-3 mb-0 text-muted text-sm">-->
<!-- <span class="text-success mr-2"><i class="fas fa-arrow-up"></i> 12%</span>-->
<!-- <span class="text-nowrap">Since last month</span>-->
<!-- </p>-->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="box admin-list-container project-language-list-container">
<table class="table table-hover text-center subject-list-table">
<thead class="thead-light">
<tr>
<th width="20%">指标名称</th>
<th width="20%">当日数</th>
<th width="20%">七日内</th>
<th width="20%">30日内</th>
<th width="20%">周用户留存率</th>
</tr>
</thead>
<tbody>
<tr class="">
<td>
<button type="button" class="btn btn-primary" style="font-size:14px;width:85px;padding: 0; height:36px;background-color:#5475fb;border-radius:4px;border-color: #5475fb;">活跃用户</button>
</td>
<td><%=@active_user_count %></td>
<td><%=@weekly_active_user_count %></td>
<td><%=@month_active_user_count %></td>
<td><%="#{@weekly_keep_rate.to_f * 100 }%" %></td>
</td>
</tr>
<tr>
<td>
<button type="button" class="btn btn-primary" style="font-size:14px;width:85px;padding: 0; height:36px;background-color:#36cfc9;border-radius:4px; border-color: #36cfc9;">新注册用户</button>
</td>
<td><%=@day_new_user_count %></td>
<td><%=@weekly_new_user_count %></td>
<td><%=@month_new_user_count %></td>
<td><%="--" %></td>
</tr>
<tr>
<td>
<button type="button" class="btn btn-primary" style="font-size:14px;width:85px;padding: 0; height:36px;background-color:#f89422;border-radius:4px; border-color: #f89422;">活跃项目</button>
</td>
<td><%=@day_active_project_count %></td>
<td><%=@weekly_active_project_count %></td>
<td><%=@month_active_project_count %></td>
<td><%="--" %></td>
</tr>
<tr>
<td>
<button type="button" class="btn btn-primary" style="font-size:14px;width:85px;padding: 0; height:36px;background-color:#9d74ff;border-radius:4px; border-color: #9d74ff;">新增项目</button>
</td>
<td><%=@day_new_project_count %></td>
<td><%=@weekly_new_project_count %></td>
<td><%=@month_new_project_count %></td>
<td><%="--" %></td>
</tr>
</tbody>
</table>
</div>

<div class="container-fluid mt--7 pie-statistic">
<div class="row mt-5">
<div class="col-xl-8 mb-5 mb-xl-0">
<div class="card shadow">
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <h5 class="mb-0">近7天评测次数</h5>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <div id="evaluate-pie" class="pie"></div>-->
<!-- </div>-->
</div>
</div>

<div class="col-xl-4">
<div class="card shadow">
<div class="card-header border-0">
<div class="row align-items-center">
<h5 class="mb-0">30天内新增用户</h5>
</div>
</div>
<div class="table-responsive">
<div id="month-active-user" class="pie"></div>
</div>
</div>
</div>
</div>
</div>


<!--<div class="container-fluid mt--7">-->
<!-- <div class="row mt-5">-->
<!-- <div class="col-xl-8 mb-5 mb-xl-0">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Page visits</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">/test/</th>-->
<!-- <td>4,569</td>-->
<!-- <td>340</td>-->
<!-- <td>-->
<!-- <i class="fas fa-arrow-up text-success mr-3"></i> 46,53%-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="col-xl-4">-->
<!-- <div class="card shadow">-->
<!-- <div class="card-header border-0">-->
<!-- <div class="row align-items-center">-->
<!-- <div class="col">-->
<!-- <h3 class="mb-0">Test</h3>-->
<!-- </div>-->
<!-- <div class="col text-right">-->
<!-- <a href="#!" class="btn btn-sm btn-primary">Test</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- <div class="table-responsive">-->
<!-- <table class="table align-items-center table-flush">-->
<!-- <thead class="thead-light">-->
<!-- <tr>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col">Test</th>-->
<!-- <th scope="col"></th>-->
<!-- </tr>-->
<!-- </thead>-->
<!-- <tbody>-->
<%# 5.times do %>
<!-- <tr>-->
<!-- <th scope="row">-->
<!-- Test-->
<!-- </th>-->
<!-- <td>-->
<!-- 1,480-->
<!-- </td>-->
<!-- <td>-->
<!-- <div class="d-flex align-items-center">-->
<!-- <span class="mr-2">60%</span>-->
<!-- <div>-->
<!-- <div class="progress">-->
<!-- <div class="progress-bar bg-gradient-danger" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;"></div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </td>-->
<!-- </tr>-->
<%# end %>
<!-- </tbody>-->
<!-- </table>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
<div id="project-language-modals">
</div>

+ 10
- 0
app/views/api/v1/projects/_simple_detail.json.jbuilder View File

@@ -0,0 +1,10 @@
if project.present?
json.type project.project_type
json.(project,
:description, :forked_count, :forked_from_project_id, :identifier,
:issues_count, :pull_requests_count, :invite_code, :website, :platform,
:name, :open_devops, :praises_count, :is_public, :status, :watchers_count,
:ignore_id, :license_id, :project_category_id, :project_language_id)
else
json.nil!
end

+ 40
- 0
app/views/api/v1/projects/_simple_gitea_diff_detail.json.jbuilder View File

@@ -0,0 +1,40 @@
json.file_nums diff['NumFiles']
json.total_addition diff['TotalAddition']
json.total_deletion diff['TotalDeletion']
json.files diff['Files'].each do |file|
json.name file['Name']
json.oldname file['OldName']
json.addition file['Addition']
json.deletion file['Deletion']
json.type file['Type']
json.is_created file['IsCreated']
json.is_deleted file['IsDeleted']
json.is_bin file['IsBin']
json.is_lfs_file file['IsLFSFile']
json.is_renamed file['IsRenamed']
json.is_ambiguous file['IsAmbiguous']
json.is_submodule file['IsSubmodule']
json.sections file['Sections'] do |section|
json.file_name section['FileName']
json.name section['Name']
json.lines section['Lines'] do |line|
json.left_index line['LeftIdx']
json.right_index line['RightIdx']
json.match line['Match']
json.type line['Type']
json.content line['Content']
unless line['SectionInfo'].blank?
json.section_path line['SectionInfo']['Path']
json.section_last_left_index line['SectionInfo']['LastLeftIdx']
json.section_last_right_index line['SectionInfo']['LastRightIdx']
json.section_left_index line['SectionInfo']['LeftIdx']
json.section_right_index line['SectionInfo']['RightIdx']
json.section_left_hunk_size line['SectionInfo']['LeftHunkSize']
json.section_right_hunk_size line['SectionInfo']['RightHunkSize']
end
end
end
json.is_incomplete file['IsIncomplete']
json.is_incomplete_line_too_long file['IsIncompleteLineTooLong']
json.is_protected file['IsProtected']
end

+ 22
- 0
app/views/api/v1/projects/blame.json.jbuilder View File

@@ -0,0 +1,22 @@
json.file_size @result_object['file_size']
json.file_name @result_object['file_name']
json.num_lines @result_object['num_lines']
json.blame_parts @result_object['blame_parts'] do |part|
json.commit do
json.sha part['commit']['id']
json.author do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(part['commit']['author']), name: part['commit']['author']['Name'] }
end
json.committer do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(part['commit']['commiter']), name: part['commit']['commiter']['Name'] }
end
json.commit_message part['commit']['commit_message']
json.authored_time render_unix_time(part['commit']['authored_time'])
json.committed_time render_unix_time(part['commit']['committed_time'])
json.created_time render_unix_time(part['commit']['created_time'])
end
json.current_number part['current_number']
json.effect_line part['effect_line']
json.lines part['lines']
end

+ 4
- 0
app/views/api/v1/projects/branches/_simple_detail.json.jbuilder View File

@@ -0,0 +1,4 @@
json.name branch
json.http_url render_http_url(@project)
json.zip_url render_zip_url(@owner, @project.repository, branch)
json.tar_url render_tar_url(@owner, @project.repository, branch)

+ 26
- 0
app/views/api/v1/projects/branches/_simple_gitea_detail.json.jbuilder View File

@@ -0,0 +1,26 @@
json.name branch['name']
json.commit do
json.id branch['commit']['id']
json.message branch['commit']['message']
json.author do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(branch['commit']['author']), name: branch['commit']['author']['name'] }
end
json.committer do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(branch['commit']['committer']), name: branch['commit']['committer']['name'] }
end
json.time_ago time_from_now(branch['commit']['timestamp'].to_time)
json.timestamp branch['commit']['timestamp']
end

json.protected branch['protected']
json.user_can_push branch['user_can_push']
json.user_can_merge branch['user_can_merge']
json.commit_id branch['commit_id']
json.commit_time_from_now time_from_now(branch['commit_time'].to_time)
json.commit_time branch['commit_time']
json.default_branch branch['default_branch']
json.http_url render_http_url(@project)
json.zip_url render_zip_url(@owner, @project.repository, branch['name'])
json.tar_url render_tar_url(@owner, @project.repository, branch['name'])

+ 3
- 0
app/views/api/v1/projects/branches/all.json.jbuilder View File

@@ -0,0 +1,3 @@
json.array! @result_object["branch_name"] do |branch|
json.partial! "api/v1/projects/branches/simple_detail", branch: branch
end

+ 1
- 0
app/views/api/v1/projects/branches/create.json.jbuilder View File

@@ -0,0 +1 @@
json.partial! "api/v1/projects/branches/simple_gitea_detail", branch: @result_object

+ 10
- 0
app/views/api/v1/projects/commits/_simple_gitea_detail.json.jbuilder View File

@@ -0,0 +1,10 @@
json.sha commit['sha']
json.author do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['author']), name: commit['author']['name'] }
end

json.committer do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['committer']), name: commit['committer']['name'] }
end
json.commit_message commit['message']
json.parent_shas commit['parents'].map{|x|x['sha']}

+ 1
- 0
app/views/api/v1/projects/commits/diff.json.jbuilder View File

@@ -0,0 +1 @@
json.partial! "api/v1/projects/simple_gitea_diff_detail", diff: @result_object

+ 17
- 0
app/views/api/v1/projects/commits/index.json.jbuilder View File

@@ -0,0 +1,17 @@
json.total_count @result_object[:total_data].to_i
json.commits @result_object[:data].each do |commit|
json.sha commit['sha']
json.author do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['commit']['author']), name: commit['commit']['author']['name'] }
end
json.committer do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['commit']['committer']), name: commit['commit']['committer']['name'] }
end
json.commit_message commit['commit']['message']
json.parent_shas commit['parents'].map{|x|x['sha']}
json.files commit['files'].map{|f|f['filename']}
json.commit_date commit['commit_date']
json.commit_time render_unix_time(commit['commit']['committer']['date'])
json.branch commit['branch']
end

+ 18
- 0
app/views/api/v1/projects/compare.json.jbuilder View File

@@ -0,0 +1,18 @@
json.commits_count @result_object['CommitsCount']
json.last_commit_sha @result_object['LatestSha']
json.commits @result_object['Commits'] do |commit|
json.author do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['Author']), name: commit['Author']['Name'] }
end
json.committer do
json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(commit['Committer']), name: commit['Committer']['Name'] }
end
json.branch commit['Branch']
json.commit_message commit['CommitMessage']
json.sha commit['Sha']
json.parent_shas commit['Sha']['ParentShas']
end
json.diff do
json.partial! "api/v1/projects/simple_gitea_diff_detail", diff: @result_object['Diff']
end

+ 14
- 0
app/views/api/v1/projects/contents/batch.json.jbuilder View File

@@ -0,0 +1,14 @@
json.commit do
json.partial! "api/v1/projects/commits/simple_gitea_detail", commit: @result_object['commit']
json.authored_time render_unix_time(@result_object['commit']['author']['date'])
json.commited_time render_unix_time(@result_object['commit']['committer']['date'])
end
json.contents @result_object['contents'].each do |content|
json.name content['name']
json.path content['path']
json.sha content['sha']
json.type content['type']
json.size content['size']
json.encoding content['encoding']
json.content content['content']
end

+ 4
- 0
app/views/api/v1/projects/git/blobs.json.jbuilder View File

@@ -0,0 +1,4 @@
json.sha @result_object['sha']
json.size @result_object['size']
json.encoding @result_object['encoding']
json.content @result_object['content']

+ 9
- 0
app/views/api/v1/projects/git/trees.json.jbuilder View File

@@ -0,0 +1,9 @@
json.total_count @result_object['total_count']
json.sha @result_object['sha']
json.entries @result_object['tree'].each do |entry|
json.name entry['path']
json.mode entry['mode']
json.type entry['type'] === 'blob' ? 'file' : 'dir'
json.size entry['size']
json.sha entry['sha']
end

+ 5
- 0
app/views/api/v1/projects/show.json.jbuilder View File

@@ -0,0 +1,5 @@
json.owner do
json.partial! "api/v1/users/simple_user", user: @result_object[:owner]
end
json.(@result_object, :full_name, :ssh_url, :clone_url, :default_branch, :empty, :branch_count, :tag_count)
json.partial! "api/v1/projects/simple_detail", project: @project

+ 3
- 0
app/views/api/v1/projects/webhooks/_simple_detail.json.jbuilder View File

@@ -0,0 +1,3 @@
json.(webhook, :id, :url, :http_method, :is_active)
json.last_status webhook.last_status
json.create_time Time.at(webhook.created_unix).strftime("%Y-%m-%d %H:%M:%S")

+ 8
- 0
app/views/api/v1/projects/webhooks/_simple_gitea_detail.json.jbuilder View File

@@ -0,0 +1,8 @@
json.id webhook["id"]
json.content_type webhook['config']['content_type']
json.http_method webhook['config']['http_method']
json.url webhook['config']['url']
json.events webhook['events']
json.active webhook['active']
json.branch_filter webhook['branch_filter']
json.created_at format_time(webhook['created_at'].to_time)

+ 1
- 0
app/views/api/v1/projects/webhooks/create.json.jbuilder View File

@@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

+ 6
- 0
app/views/api/v1/projects/webhooks/hooktasks.json.jbuilder View File

@@ -0,0 +1,6 @@
json.total_count @hooktasks.total_count
json.hooktasks @hooktasks.each do |task|
json.(task, :id, :event_type, :type, :uuid, :is_succeed, :is_delivered, :payload_content, :request_content)
json.response_content task.response_content_json
json.delivered_time Time.at(task.delivered*10**-9).strftime("%Y-%m-%d %H:%M:%S")
end

+ 4
- 0
app/views/api/v1/projects/webhooks/index.json.jbuilder View File

@@ -0,0 +1,4 @@
json.total_count @webhooks.total_count
json.webhooks @webhooks do |webhook|
json.partial! "api/v1/projects/webhooks/simple_detail", webhook: webhook
end

+ 1
- 0
app/views/api/v1/projects/webhooks/show.json.jbuilder View File

@@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

+ 1
- 0
app/views/api/v1/projects/webhooks/update.json.jbuilder View File

@@ -0,0 +1 @@
json.partial! "api/v1/projects/webhooks/simple_gitea_detail", webhook: @result_object

+ 21
- 0
app/views/api/v1/users/_commit_user.json.jbuilder View File

@@ -0,0 +1,21 @@
if user.present?
if user.is_a?(Hash)
json.id user["id"]
json.login user["login"]
json.name user["name"]
json.type user["type"]
json.image_url user["avatar_url"]
else
json.id user.id
json.login user.login
json.name user.real_name
json.type user&.type
json.image_url url_to_avatar(user)
end
else
json.id nil
json.login name
json.name name
json.type nil
json.image_url User::Avatar.get_letter_avatar_url(name)
end

+ 9
- 0
app/views/api/v1/users/_simple_user.json.jbuilder View File

@@ -0,0 +1,9 @@
if user.present?
json.id user.id
json.type user.type
json.name user.real_name
json.login user.login
json.image_url url_to_avatar(user)
else
json.nil!
end

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save