diff --git a/.gitignore b/.gitignore index 6b4fd25c..d3bbe309 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,7 @@ vendor/bundle/ /log /public/admin /mysql_data +/public/repo/ .generators diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e2bb83ff..cc13d90f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -770,7 +770,7 @@ class ApplicationController < ActionController::Base end def base_url - request.base_url + Rails.application.config_for(:configuration)['platform_url'] || request.base_url end def convert_image! diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index 63ca58aa..bc81da56 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -6,26 +6,48 @@ class CompareController < ApplicationController end def show + load_compare_params compare + @merge_status, @merge_message = get_merge_message end private + def get_merge_message + if @base.blank? || @head.blank? + return -2, "请选择分支" + else + if @head.include?(":") + fork_project = @project.forked_projects.joins(:owner).where(users: {login: @head.to_s.split("/")[0]}).take + return -2, "请选择正确的仓库" unless fork_project.present? + @exist_pullrequest = @project.pull_requests.where(is_original: true, head: @head.to_s.split(":")[1], base: @base, status: 0, fork_project_id: fork_project.id).take + else + @exist_pullrequest = @project.pull_requests.where(is_original: false, head: @base, base: @head, status: 0).take + end + if @exist_pullrequest.present? + return -2, "在这些分支之间的合并请求已存在:#{@exist_pullrequest.try(:title)}" + else + if @compare_result["Commits"].blank? && @compare_result["Diff"].blank? + return -2, "分支内容相同,无需创建合并请求" + end + end + end + return 0, "可以合并" + end + def compare - base, head = compare_params # TODO: 处理fork的项目向源项目发送PR的base、head参数问题 @compare_result ||= - head.include?(":") ? gitea_compare(base, head) : gitea_compare(head, base) + @head.include?(":") ? gitea_compare(@base, @head) : gitea_compare(@head, @base) end - def compare_params - base = Addressable::URI.unescape(params[:base]) - head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head] + def load_compare_params + @base = Addressable::URI.unescape(params[:base]) + @head = params[:head].include?('json') ? params[:head]&.split('.json')[0] : params[:head] - [base, head] end def gitea_compare(base, head) - Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head) + Gitea::Repository::Commits::CompareService.call(@owner.login, @project.identifier, base, head, current_user.gitea_token) end end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 4b073415..3af2f653 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -3,6 +3,7 @@ class IssuesController < ApplicationController before_action :load_project before_action :set_user before_action :check_issue_permission + before_action :operate_issue_permission, only:[:create, :update, :destroy, :clean, :series_update, :copy] before_action :check_project_public, only: [:index ,:show, :copy, :index_chosen, :close_issue] before_action :set_issue, only: [:edit, :update, :destroy, :show, :copy, :close_issue, :lock_issue] @@ -230,7 +231,7 @@ class IssuesController < ApplicationController end def show - @user_permission = current_user.present? && current_user.logged? && (!@issue.is_lock || @project.member?(current_user) || current_user.admin? || @issue.user == current_user) + @user_permission = current_user.present? && current_user.logged? && (@project.member?(current_user) || current_user.admin? || @issue.user == current_user) @issue_attachments = @issue.attachments @issue_user = @issue.user @issue_assign_to = @issue.get_assign_user @@ -303,7 +304,7 @@ class IssuesController < ApplicationController if issue_ids.present? if update_hash.blank? normal_status(-1, "请选择批量更新内容") - elsif Issue.where(id: issue_ids).update_all(update_hash) + elsif Issue.where(id: issue_ids)&.update(update_hash) normal_status(0, "批量更新成功") else normal_status(-1, "批量更新失败") @@ -315,6 +316,7 @@ class IssuesController < ApplicationController def copy @new_issue = @issue.dup + @new_issue.author_id = current_user.id if @new_issue.save issue_tags = @issue.issue_tags.pluck(:id) if issue_tags.present? @@ -412,6 +414,10 @@ class IssuesController < ApplicationController end end + def operate_issue_permission + return render_forbidden("您没有权限进行此操作.") unless current_user.admin? || @project.member?(current_user) + end + def export_issues(issues) @table_columns = %w(ID 类型 标题 描述 状态 指派给 优先级 标签 发布人 创建时间 里程碑 开始时间 截止时间 完成度 分类 金额 属于) @export_issues = [] diff --git a/app/controllers/projects/base_controller.rb b/app/controllers/projects/base_controller.rb index 9811a213..240bc91f 100644 --- a/app/controllers/projects/base_controller.rb +++ b/app/controllers/projects/base_controller.rb @@ -4,4 +4,7 @@ class Projects::BaseController < ApplicationController before_action :load_project before_action :load_repository + def require_manager! + return render_forbidden('你没有权限操作') unless current_user.admin? || @project.manager?(current_user) + end end diff --git a/app/controllers/projects/webhooks_controller.rb b/app/controllers/projects/webhooks_controller.rb new file mode 100644 index 00000000..9f36da20 --- /dev/null +++ b/app/controllers/projects/webhooks_controller.rb @@ -0,0 +1,116 @@ +class Projects::WebhooksController < Projects::BaseController + before_action :require_manager! + before_action :find_webhook, only:[:edit, :update, :destroy, :tasks, :test] + + def index + @webhooks = @project.webhooks + @webhooks = kaminari_paginate(@webhooks) + end + + def create + ActiveRecord::Base.transaction do + return render_error("webhooks数量已到上限!请删除暂不使用的webhooks以进行添加操作") if @project.webhooks.size > 19 + return render_error("参数错误.") unless webhook_params.present? + form = Projects::Webhooks::CreateForm.new(webhook_params) + return render json: {status: -1, message: form.errors} unless form.validate! + response = Gitea::Repository::Webhooks::CreateService.new(operating_token, @project&.owner&.login, @project&.identifier, gitea_webhooks_params).call + if response[0] == 201 + @webhook = response[2] + else + render_error("创建失败.") + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def edit + + end + + def update + return render_error("参数错误.") unless webhook_params.present? + form = Projects::Webhooks::CreateForm.new(webhook_params) + return render json: {status: -1, message: form.errors} unless form.validate! + response = Gitea::Repository::Webhooks::UpdateService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id, gitea_webhooks_params) + if response[0] == 200 + @webhook = response[2] + render_ok + else + render_error("更新失败.") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def destroy + response = Gitea::Repository::Webhooks::DeleteService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id) + if response[0] == 204 + @webhook = response[2] + render_ok + else + render_error("删除失败.") + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def tasks + @tasks = @webhook.tasks.where(is_delivered: true).order("delivered desc") + @tasks = kaminari_paginate(@tasks) + end + + def test + ActiveRecord::Base.transaction do + response = Gitea::Repository::Webhooks::TestService.call(operating_token, @project&.owner&.login, @project&.identifier, @webhook.id) + if response[0] == 204 + render_ok + else + render_error("测试推送失败.") + end + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + def find_webhook + @webhook = @project.webhooks.find_by_id(params[:id]) + return render_not_found if @webhook.nil? + end + + def webhook_params + params.require(:webhook).permit(:url, :type, :http_method, :content_type, :secret, :active, :branch_filter, events: []) + end + + def webhook_type + webhook_params.fetch(:type, "gitea") + end + + def webhook_branch_filter + webhook_params.fetch(:branch_filter, "*") + end + + def gitea_webhooks_params + { + active: webhook_params[:active], + branch_filter: webhook_branch_filter, + config: { + content_type: webhook_params[:content_type], + url: webhook_params[:url], + http_method: webhook_params[:http_method], + secret: webhook_params[:secret] + }, + events: webhook_params[:events], + type: webhook_type, + } + end + + def operating_token + @project.member?(current_user) ? current_user.gitea_token : @project&.owner&.gitea_token + end +end \ No newline at end of file diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 3e40619c..fee3ae75 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -5,7 +5,7 @@ class ProjectsController < ApplicationController include Acceleratorable before_action :require_login, except: %i[index branches group_type_list simple show fork_users praise_users watch_users recommend about menu_list] - before_action :load_project, except: %i[index group_type_list migrate create recommend] + before_action :load_repository, except: %i[index group_type_list migrate create recommend] before_action :authorizate_user_can_edit_project!, only: %i[update] before_action :project_public?, only: %i[fork_users praise_users watch_users] @@ -116,10 +116,11 @@ class ProjectsController < ApplicationController Projects::UpdateForm.new(validate_params).validate! - private = params[:private] || false + private = @project.forked_from_project.present? ? !@project.forked_from_project.is_public : params[:private] || false new_project_params = project_params.except(:private).merge(is_public: !private) @project.update_attributes!(new_project_params) + @project.forked_projects.update_all(is_public: @project.is_public) gitea_params = { private: private, default_branch: @project.default_branch, @@ -144,6 +145,7 @@ class ProjectsController < ApplicationController ActiveRecord::Base.transaction do Gitea::Repository::DeleteService.new(@project.owner, @project.identifier).call @project.destroy! + @project.forked_projects.update_all(forked_from_project_id: nil) render_ok end else diff --git a/app/controllers/public_keys_controller.rb b/app/controllers/public_keys_controller.rb new file mode 100644 index 00000000..327e719c --- /dev/null +++ b/app/controllers/public_keys_controller.rb @@ -0,0 +1,64 @@ +class PublicKeysController < ApplicationController + before_action :require_login + before_action :find_public_key, only: [:destroy] + + def index + @public_keys = current_user.public_keys + @public_keys = kaminari_paginate(@public_keys) + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def create + return render_error("参数错误") if public_key_params.blank? + return render_ok({status: 10002, message: "请输入密钥"}) if public_key_params[:key].blank? + return render_ok({status: 10001, message: "请输入标题"}) if public_key_params[:title].blank? + @gitea_response = Gitea::User::Keys::CreateService.call(current_user.gitea_token, public_key_params) + if @gitea_response[0] == 201 + @public_key = @gitea_response[2] + else + return render_error("创建ssh key失败") if @gitea_response[2].blank? + return render_ok({status: 10002, message: "密钥格式不正确"}) if @gitea_response[2]["message"].starts_with?("Invalid key content") + exist_public_key = Gitea::PublicKey.find_by(content: public_key_params[:key]) + return render_ok({status: 10002, message: "密钥已被占用"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key") && exist_public_key.present? && exist_public_key&.owner_id != current_user.gitea_uid + return render_ok({status: 10002, message: "密钥已存在,请勿重复添加"}) if @gitea_response[2]["message"].starts_with?("Key content has been used as non-deploy key") + @public_key = nil + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + def destroy + return render_not_found unless @public_key.present? + result = Gitea::User::Keys::DeleteService.call(current_user.gitea_token, @public_key.id) + if result[0] == 204 + render_ok + else + render_error + end + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + end + + private + + def page + params[:page].to_i.zero? ? 1 : params[:page].to_i + end + + def limit + limit = params[:limit] || params[:per_page] + limit = (limit.to_i.zero? || limit.to_i > 15) ? 15 : limit.to_i + end + + def public_key_params + params.require(:public_key).permit(:key, :title) + end + + def find_public_key + @public_key = current_user.public_keys.find_by_id(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/pull_requests_controller.rb b/app/controllers/pull_requests_controller.rb index 8521cd4b..4270cb38 100644 --- a/app/controllers/pull_requests_controller.rb +++ b/app/controllers/pull_requests_controller.rb @@ -56,7 +56,7 @@ class PullRequestsController < ApplicationController ActiveRecord::Base.transaction do @pull_request, @gitea_pull_request = PullRequests::CreateService.call(current_user, @owner, @project, params) if @gitea_pull_request[:status] == :success - @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"]) + @pull_request.bind_gitea_pull_request!(@gitea_pull_request[:body]["number"], @gitea_pull_request[:body]["id"]) render_ok else render_error("create pull request error: #{@gitea_pull_request[:status]}") @@ -91,7 +91,7 @@ class PullRequestsController < ApplicationController if @issue.update_attributes(@issue_params) if @pull_request.update_attributes(@local_params.compact) gitea_pull = Gitea::PullRequest::UpdateService.call(@owner.login, @repository.identifier, - @pull_request.gpid, @requests_params, current_user.gitea_token) + @pull_request.gitea_number, @requests_params, current_user.gitea_token) if gitea_pull[:status] === :success if params[:issue_tag_ids].present? @@ -139,7 +139,7 @@ class PullRequestsController < ApplicationController @issue_user = @issue.user @issue_assign_to = @issue.get_assign_user @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, - @repository.identifier, @pull_request.gpid, current_user&.gitea_token) + @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) end def pr_merge @@ -150,9 +150,16 @@ class PullRequestsController < ApplicationController else ActiveRecord::Base.transaction do begin - result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params) + @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) - if result.status == 200 && @pull_request.merge! + if @gitea_pull["merged_by"].present? + success_condition = true + else + result = PullRequests::MergeService.call(@owner, @repository, @pull_request, current_user, params) + success_condition = result.status == 200 + end + + if success_condition && @pull_request.merge! @pull_request.project_trend_status! @issue&.custom_journal_detail("merge", "", "该合并请求已被合并", current_user&.id) normal_status(1, "合并成功") @@ -191,12 +198,12 @@ class PullRequestsController < ApplicationController def files - @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token) + @files_result = Gitea::PullRequest::FilesService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token) # render json: @files_result end def commits - @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gpid, current_user&.gitea_token) + @commits_result = Gitea::PullRequest::CommitsService.call(@owner.login, @project.identifier, @pull_request.gitea_number, current_user&.gitea_token) # render json: @commits_result end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 93ba02a9..f375b636 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -5,9 +5,9 @@ class RepositoriesController < ApplicationController before_action :require_login, only: %i[edit update create_file update_file delete_file sync_mirror] before_action :load_repository - before_action :authorizate!, except: [:sync_mirror, :tags, :commit] + 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] + before_action :get_ref, only: %i[entries sub_entries top_counts file archive] before_action :get_latest_commit, only: %i[entries sub_entries top_counts] before_action :get_statistics, only: %i[top_counts] @@ -192,6 +192,19 @@ class RepositoriesController < ApplicationController render json: languages_precentagable end + def archive + domain = Gitea.gitea_config[:domain] + api_url = Gitea.gitea_config[:base_url] + archive_url = "/repos/#{@owner.login}/#{@repository.identifier}/archive/#{params[:archive]}" + + file_path = [domain, api_url, archive_url].join + file_path = [file_path, "access_token=#{current_user&.gitea_token}"].join("?") if @repository.hidden? + + return render_not_found if !request.format.zip? && !request.format.gzip? + + redirect_to file_path + end + private def find_project @@ -266,7 +279,7 @@ class RepositoriesController < ApplicationController # uploadPushInfo end - + def create_new_pr(params) if params[:new_branch].present? && params[:new_branch] != params[:branch] local_params = { @@ -303,7 +316,7 @@ class RepositoriesController < ApplicationController local_requests = PullRequest.new(local_params.merge(user_id: current_user.try(:id), project_id: @project.id, issue_id: @pull_issue.id)) if local_requests.save gitea_request = Gitea::PullRequest::CreateService.new(current_user.try(:gitea_token), @owner.login, @project.try(:identifier), requests_params).call - if gitea_request[:status] == :success && local_requests.update_attributes(gpid: gitea_request["body"]["number"]) + if gitea_request[:status] == :success && local_requests.update_attributes(gitea_number: gitea_request["body"]["number"]) local_requests.project_trends.create(user_id: current_user.id, project_id: @project.id, action_type: "create") end end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index f5d09ed3..58cd9e87 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -25,17 +25,13 @@ class VersionsController < ApplicationController end def show - version_issues = @version.issues.issue_includes + version_issues = @version.issues.issue_issue.issue_includes status_type = params[:status_type] || "1" # @close_issues_size = version_issues.where(status_id: 5).size # @open_issues_size = version_issues.size - @close_issues_size - if status_type.to_s == "1" #表示开启中的 - version_issues = version_issues.where.not(status_id: 5) - else - version_issues = version_issues.where(status_id: 5) - end + version_issues = version_issues.where(author_id: params[:author_id]) if params[:author_id].present? && params[:author_id].to_s != "all" version_issues = version_issues.where(assigned_to_id: params[:assigned_to_id]) if params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all" version_issues = version_issues.where(tracker_id: params[:tracker_id]) if params[:tracker_id].present? && params[:tracker_id].to_s != "all" @@ -47,10 +43,26 @@ class VersionsController < ApplicationController version_issues = version_issues.joins(:issue_tags).where(issue_tags: {id: params[:issue_tag_id].to_i}) if params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all" version_issues = version_issues.reorder("#{order_name} #{order_type}") + has_filter_params = (params[:author_id].present? && params[:author_id].to_s != "all") || + (params[:assigned_to_id].present? && params[:assigned_to_id].to_s != "all") || + (params[:tracker_id].present? && params[:tracker_id].to_s != "all") || + (params[:status_id].present? && params[:status_id].to_s != "all") || + (params[:priority_id].present? && params[:priority_id].to_s != "all") || + (params[:fixed_version_id].present? && params[:fixed_version_id].to_s != "all") || + (params[:done_ratio].present? && params[:done_ratio].to_s != "all") || + (params[:issue_type].present? && params[:issue_type].to_s != "all") || + (params[:issue_tag_id].present? && params[:issue_tag_id].to_s != "all") + @version_close_issues_size = has_filter_params ? version_issues.closed.size : @version.issues.issue_issue.issue_includes.closed.size + @version_issues_size = has_filter_params ? version_issues.size : @version.issues.issue_issue.issue_includes.size + if status_type.to_s == "1" #表示开启中的 + version_issues = version_issues.where.not(status_id: 5) + else + version_issues = version_issues.where(status_id: 5) + end @page = params[:page] || 1 @limit = params[:limit] || 15 - @version_issues_size = version_issues.size + # @version_issues_size = version_issues.size @version_issues = version_issues.page(@page).per(@limit) end diff --git a/app/docs/slate/source/api.html.md b/app/docs/slate/source/api.html.md index a08823a4..a846317c 100644 --- a/app/docs/slate/source/api.html.md +++ b/app/docs/slate/source/api.html.md @@ -12,6 +12,7 @@ toc_footers: includes: - licenses - gitignores + - public_keys - users - projects - repositories diff --git a/app/docs/slate/source/includes/_public_keys.md b/app/docs/slate/source/includes/_public_keys.md new file mode 100644 index 00000000..60d73c01 --- /dev/null +++ b/app/docs/slate/source/includes/_public_keys.md @@ -0,0 +1,158 @@ + +# PublicKeys + +## public_keys列表 +获取public_keys列表,支持分页 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/public_keys.json +``` + +```javascript +await octokit.request('GET /api/public_keys.json') +``` + +### HTTP 请求 +`GET api/public_keys.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +page |否| 1 | int | 页码 | +limit |否| 15 | int | 每页数量 | + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +total_count |int |总数 | +public_keys.id |int |ID| +public_keys.name |string|密钥标题| +public_keys.content |string|密钥内容| +public_keys.fingerprint |string|密钥标识| +public_keys.created_time |string|密钥创建时间| + + +> 返回的JSON示例: + +```json +{ + "total_count": 1, + "public_keys": [ + { + "id": 16, + "name": "xxx", + "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com", + "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM", + "created_unix": 1626246596, + "created_time": "2021/07/14 15:09" + } + ] +} +``` + + +## 创建public_key +创建public_key + +> 示例: + +```shell +curl -X POST \ +http://localhost:3000/api/public_keys.json +``` + +```javascript +await octokit.request('POST /api/public_keys.json') +``` + +### HTTP 请求 +`POST api/public_keys.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +key |是 | 否 | string | 密钥 | +title |是 | 否 | string | 密钥标题 | + +> 请求的JSON示例: +```json +{ + "public_key": { + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com", + "title": "xxx" + } +} +``` + +### 返回字段说明 +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +total_count |int |总数 | +id |int |ID| +name |string|密钥标题| +content |string|密钥内容| +fingerprint |string|密钥标识| +created_time |string|密钥创建时间| + + +> 返回的JSON示例: + +```json +{ + "id": 17, + "name": "xxx", + "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com", + "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM", + "created_time": "2021/07/14 15:26" +} +``` + + + +## 删除public_key +删除public_key + +> 示例: + +```shell +curl -X DELETE \ +http://localhost:3000/api/public_keys/:id.json +``` + +```javascript +await octokit.request('DELETE /api/public_keys/:id.json') +``` + +### HTTP 请求 +`DELETE api/public_keys/:id.json` + +### 请求参数 +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +id |是 | 否 | int | 密钥ID | + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + diff --git a/app/docs/slate/source/includes/_repositories.md b/app/docs/slate/source/includes/_repositories.md index 40d3ba2f..1552655e 100644 --- a/app/docs/slate/source/includes/_repositories.md +++ b/app/docs/slate/source/includes/_repositories.md @@ -867,3 +867,674 @@ await octokit.request('GET /api/jasder/jasder_test/sub_entries.json') + +## 获取仓库webhooks列表 +获取仓库webhooks列表 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/yystopf/ceshi/webhooks.json +``` + +```javascript +await octokit.request('GET /api/yystopf/ceshi/webhooks.json') +``` + +### HTTP 请求 +`GET /api/:owner/:repo/webhooks.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| |string |用户登录名 | +|repo |是| |string |项目标识identifier | + + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |id | +|url |string|地址| +|http_method |string|请求方式| +|is_active |bool |是否激活| +|type |string|类型| +|last_status |string|最后一次推送的状态| +|create_time |string|创建时间| + + +> 返回的JSON示例: + +```json +{ + "total_count": 4, + "webhooks": [ + { + "id": 2, + "url": "https://oapi.dingtalk.com/robot/send?access_token=7e1e19d0eddb6a5e33c5c2c4e66f4c88f9437184b9ed2c2653194c6374c7d513", + "http_method": "", + "is_active": true, + "type": "dingtalk", + "last_status": "succeed", + "create_time": "2021-07-12 10:50:07" + }, + { + "id": 3, + "url": "http://localhost:3000", + "http_method": "GET", + "is_active": true, + "type": "gitea", + "last_status": "succeed", + "create_time": "2021-07-26 10:03:45" + }, + { + "id": 4, + "url": "http://localhost:10081", + "http_method": "POST", + "is_active": true, + "type": "gitea", + "last_status": "waiting", + "create_time": "2021-07-26 16:56:53" + }, + { + "id": 5, + "url": "http://localhost:3001", + "http_method": "POST", + "is_active": true, + "type": "gitea", + "last_status": "fail", + "create_time": "2021-07-26 16:58:23" + } + ] +} +``` + + +## 获取仓库单个webhook +获取仓库单个webhook + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/yystopf/ceshi/webhooks/3/edit.json +``` + +```javascript +await octokit.request('GET /api/yystopf/ceshi/webhooks/3/edit.json') +``` + +### HTTP 请求 +`GET /api/:owner/:repo/webhooks/:id/edit.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| |string |用户登录名 | +|repo |是| |string |项目标识identifier | +|id |是||integer|webhook ID| + + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |id | +|url |string|地址| +|content_type |string|POST Content Type| +|http_method |string|请求方式| +|secret| |string|密钥| +|is_active |bool |是否激活| +|type |string|类型| +|last_status |string|最后一次推送的状态, waiting 等待,fail 失败,succeed 成功| +|branch_filter |string|分支过滤| +|events |string|触发条件| +|create_time |string|创建时间| + + +参数| 含义| +--------- | ------- | ------- | +|create|创建分支或标签| +|delete|分支或标签删除| +|fork|仓库被fork| +|push|git仓库推送| +|issue|易修已打开、已关闭、已重新打开或编辑| +|issue_assign|易修被指派| +|issue_label|易修标签被更新或删除| +|issue_milestone|易修被收入里程碑| +|issue_comment|易修评论| +|pull_request|合并请求| +|pull_request_assign|合并请求被指派| +|pull_request_label|合并请求被贴上标签| +|pull_request_milestone|合并请求被记录于里程碑中| +|pull_request_comment|合并请求被评论| +|pull_request_review_approved|合并请求被批准| +|pull_request_review_rejected|合并请求被拒绝| +|pull_request_review_comment|合并请求被提出审查意见| +|pull_request_sync|合并请求被同步| +|repository|创建或删除仓库| +|release|版本发布| + + +> 返回的JSON示例: + +```json +{ + "id": 3, + "http_method": "GET", + "content_type": "form", + "url": "http://localhost:3000", + "secret": "123456", + "last_status": "succeed", + "is_active": true, + "type": "gitea", + "create_time": "2021-07-26 10:03:45", + "branch_filter": "*", + "events": [ + "create", + "delete", + "fork", + "issues", + "issue_assign", + "issue_label", + "issue_milestone", + "issue_comment", + "push", + "pull_request", + "pull_request_assign", + "pull_request_label", + "pull_request_milestone", + "pull_request_comment", + "pull_request_review", + "pull_request_sync", + "repository", + "release" + ] +} +``` + + +## 添加仓库webhook +添加仓库webhook + +> 示例: + +```shell +curl -X POST \ +http://localhost:3000/api/yystopf/ceshi/webhooks.json +``` + +```javascript +await octokit.request('POST /api/yystopf/ceshi/webhooks.json') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/webhooks.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| | string |用户登录名 | +|repo |是| | string |项目标识identifier | +|webhook.url |是| | string |目标url | +|webhook.type |否| | string |类型| +|webhook.http_method |是| | string | http方法, POST和GET | +|webhook.content_type |是| | string | POST Content Type | +|webhook.secret |否| | string |密钥文本| +|webhook.active |是| | bool | 是否激活| +|webhook.branch_filter|否| |string|分支过滤| +|webhook.events |否| |array|触发事件| + +触发事件字段说明 + +参数| 含义| +--------- | ------- | ------- | +|create|创建分支或标签| +|delete|分支或标签删除| +|fork|仓库被fork| +|push|git仓库推送| +|issue|易修已打开、已关闭、已重新打开或编辑| +|issue_assign|易修被指派| +|issue_label|易修标签被更新或删除| +|issue_milestone|易修被收入里程碑| +|issue_comment|易修评论| +|pull_request|合并请求| +|pull_request_assign|合并请求被指派| +|pull_request_label|合并请求被贴上标签| +|pull_request_milestone|合并请求被记录于里程碑中| +|pull_request_comment|合并请求被评论| +|pull_request_review_approved|合并请求被批准| +|pull_request_review_rejected|合并请求被拒绝| +|pull_request_review_comment|合并请求被提出审查意见| +|pull_request_sync|合并请求被同步| +|repository|创建或删除仓库| +|release|版本发布| + + +> 请求的JSON示例: + +```json +{ + "active": true, + "content_type": "json", + "http_method": "GET", + "secret": "123456", + "url": "http://localhost:10000", + "branch_filter": "*", + "events": ["push"] +} +``` + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |id | +|url |string|地址| +|content_type |string|POST Content Type| +|is_active |bool |是否激活| +|type |string|类型| +|events | array|触发事件 | +|create_time |string|创建时间| + + +> 返回的JSON示例: + +```json +{ + "id": 18, + "type": "gitea", + "content_type": "json", + "url": "http://localhost:10000", + "events": [ + "push" + ], + "active": true, + "create_time": "2021-07-26 18:53:43" +} +``` + + +## 更新仓库webhook +更新仓库webhook + +> 示例: + +```shell +curl -X PATCH \ +http://localhost:3000/api/yystopf/ceshi/webhooks/7.json +``` + +```javascript +await octokit.request('PATCH /api/yystopf/ceshi/webhooks/7.json') +``` + +### HTTP 请求 +`PATCH /api/:owner/:repo/webhooks/:id.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| | string |用户登录名 | +|repo |是| | string |项目标识identifier | +|id |是| | string |webhook id | +|webhook.url |是| | string |目标url | +|webhook.type |否| | string |类型| +|webhook.http_method |是| | string | http方法, POST和GET | +|webhook.content_type |是| | string | POST Content Type | +|webhook.secret |否| | string |密钥文本| +|webhook.active |是| | bool | 是否激活| +|webhook.branch_filter|否| |string|分支过滤| +|webhook.events |否| |array|触发事件| + +触发事件字段说明 + +参数| 含义| +--------- | ------- | ------- | +|create|创建分支或标签| +|delete|分支或标签删除| +|fork|仓库被fork| +|push|git仓库推送| +|issue|易修已打开、已关闭、已重新打开或编辑| +|issue_assign|易修被指派| +|issue_label|易修标签被更新或删除| +|issue_milestone|易修被收入里程碑| +|issue_comment|易修评论| +|pull_request|合并请求| +|pull_request_assign|合并请求被指派| +|pull_request_label|合并请求被贴上标签| +|pull_request_milestone|合并请求被记录于里程碑中| +|pull_request_comment|合并请求被评论| +|pull_request_review_approved|合并请求被批准| +|pull_request_review_rejected|合并请求被拒绝| +|pull_request_review_comment|合并请求被提出审查意见| +|pull_request_sync|合并请求被同步| +|repository|创建或删除仓库| +|release|版本发布| + + +> 请求的JSON示例: + +```json +{ + "active": true, + "content_type": "json", + "http_method": "GET", + "secret": "123456", + "url": "http://localhost:10000", + "branch_filter": "*", + "events": ["push"] +} +``` + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + + +## 删除仓库webhook +删除仓库webhook + +> 示例: + +```shell +curl -X DELETE \ +http://localhost:3000/api/yystopf/ceshi/webhooks/7.json +``` + +```javascript +await octokit.request('DELETE /api/yystopf/ceshi/webhooks/7.json') +``` + +### HTTP 请求 +`DELETE /api/:owner/:repo/webhooks/:id.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| | string |用户登录名 | +|repo |是| | string |项目标识identifier | +|id |是| | string |webhook id | + +### 返回字段说明: + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + + +## 获取仓库webhook的历史推送列表 +获取仓库webhook的历史推送列表 + +> 示例: + +```shell +curl -X GET \ +http://localhost:3000/api/yystopf/ceshi/webhooks/3/tasks.json +``` + +```javascript +await octokit.request('GET /api/yystopf/ceshi/webhooks/3/tasks.json') +``` + +### HTTP 请求 +`GET /api/:owner/:repo/webhooks/:id/tasks.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| |string |用户登录名 | +|repo |是| |string |项目标识identifier | +|id |是| |integer |webhook ID| + +### 返回字段说明: +参数 | 类型 | 字段说明 +--------- | ----------- | ----------- +|id |int |id | +|uuid |string|推送uuid| +|type |string|类型| +|is_succeed |bool|是否推送成功| +|is_delivered |bool|是否完成推送| +|payload_content |json|请求主体内容| +|request_content |json|请求内容,头部等等| +|reponse_content |json|响应内容,状态,头部,主体等等| +|delivered_time |string|推送时间| + + +> 返回的JSON示例: + +```json +{ + "total_count": 6, + "tasks": [ + { + "id": 20, + "type": "gitea", + "uuid": "99aa2c23-6884-4c44-9020-5469320aa408", + "is_succeed": true, + "is_delivered": true, + "payload_content": { + "secret": "123456", + "ref": "refs/heads/master", + "before": "feb48e31362787a7620b53d4df3c4effddbb6f0b", + "after": "feb48e31362787a7620b53d4df3c4effddbb6f0b", + "compare_url": "", + "commits": [ + { + "id": "feb48e31362787a7620b53d4df3c4effddbb6f0b", + "message": "fix\n", + "url": "http://localhost:10081/yystopf/ceshi/commit/feb48e31362787a7620b53d4df3c4effddbb6f0b", + "author": { + "name": "viletyy", + "email": "yystopf@163.com", + "username": "root" + }, + "committer": { + "name": "viletyy", + "email": "yystopf@163.com", + "username": "root" + }, + "verification": { + "verified": false, + "reason": "gpg.error.not_signed_commit", + "signature": "", + "signer": null, + "payload": "" + }, + "timestamp": "2021-07-26T13:52:13+08:00", + "added": null, + "removed": null, + "modified": null + } + ], + "head_commit": null, + "repository": { + "id": 2, + "owner": { + "id": 3, + "login": "yystopf", + "full_name": "", + "email": "yystopf@forge.com", + "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1", + "language": "zh-CN", + "is_admin": true, + "last_login": "2021-07-21T18:38:21+08:00", + "created": "2021-06-03T14:50:25+08:00", + "username": "yystopf" + }, + "name": "ceshi", + "full_name": "yystopf/ceshi", + "description": "", + "empty": false, + "private": false, + "fork": false, + "template": false, + "parent": null, + "mirror": false, + "size": 3846, + "html_url": "http://localhost:10081/yystopf/ceshi", + "ssh_url": "virus@localhost:10081:yystopf/ceshi.git", + "clone_url": "http://localhost:10081/yystopf/ceshi.git", + "original_url": "", + "website": "", + "stars_count": 0, + "forks_count": 1, + "watchers_count": 1, + "open_issues_count": 0, + "open_pr_counter": 0, + "release_counter": 0, + "default_branch": "master", + "archived": false, + "created_at": "2021-06-03T15:15:30+08:00", + "updated_at": "2021-07-26T13:52:16+08:00", + "permissions": { + "admin": false, + "push": false, + "pull": false + }, + "has_issues": true, + "internal_tracker": { + "enable_time_tracker": true, + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true + }, + "has_wiki": true, + "has_pull_requests": true, + "ignore_whitespace_conflicts": false, + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "avatar_url": "", + "internal": false + }, + "pusher": { + "id": 0, + "login": "yystopf", + "full_name": "", + "email": "yystopf@forge.com", + "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-06-03T14:50:25+08:00", + "username": "yystopf" + }, + "sender": { + "id": 0, + "login": "yystopf", + "full_name": "", + "email": "yystopf@forge.com", + "avatar_url": "http://localhost:10081/user/avatar/yystopf/-1", + "language": "", + "is_admin": false, + "last_login": "0001-01-01T00:00:00Z", + "created": "2021-06-03T14:50:25+08:00", + "username": "yystopf" + } + }, + "request_content": { + "headers": { + "X-GitHub-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408", + "X-GitHub-Event": "push", + "X-Gitea-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408", + "X-Gitea-Event": "push", + "X-Gitea-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66", + "X-Gogs-Delivery": "99aa2c23-6884-4c44-9020-5469320aa408", + "X-Gogs-Event": "push", + "X-Gogs-Signature": "34a01edcd952ff6410ff6ebc946471161bde74aff86171f21621d2c2c4130f66" + } + }, + "response_content": { + "status": 200, + "headers": { + "Cache-Control": "no-store, must-revalidate, private, max-age=0", + "Content-Length": "2556", + "Content-Type": "text/html; charset=utf-8", + "Referrer-Policy": "strict-origin-when-cross-origin", + "Set-Cookie": "__profilin=p%3Dt; path=/; HttpOnly", + "Vary": "Origin", + "X-Content-Type-Options": "nosniff", + "X-Download-Options": "noopen", + "X-Frame-Options": "SAMEORIGIN", + "X-Miniprofiler-Ids": "9ynvpncz5xm0rpgorb5y,hgggd9mv6lr4a9drcrlr,j7zqlx2vy5aji2vtgoba,f1ktsmh3jxvq0z2hf612,mih3dvgvlqhi3zy8lf2x,5k1qbkvbnru8mye9cest,tj6ern8w6awqf2zsimbr,9isaehvubivd52wo5p9v,1rzfhtq1nhuwbgy9p76g,z0xzidzyywna0y7a69m0,hzoklky92ycjqt42gi0s,y0ai7y0t28mcn8x0py2x,322il7nadinp51mw2r5m,m6dukftfsh6tjcxzp1gq,667wlqbytfwbrirnmma1,jcehj3dl8lkw8gk510cr", + "X-Miniprofiler-Original-Cache-Control": "max-age=0, private, must-revalidate", + "X-Permitted-Cross-Domain-Policies": "none", + "X-Request-Id": "08bff080-bbb5-4183-b845-81de3d47120a", + "X-Runtime": "0.394766", + "X-Xss-Protection": "1; mode=block" + }, + "body": "
\n" + }, + "delivered_time": "2021-07-28 11:47:29" + } + ] +} +``` + + +## 仓库webhook测试推送 +仓库webhook测试推送 + +> 示例: + +```shell +curl -X POST \ +http://localhost:3000/api/yystopf/ceshi/webhooks/3/test.json +``` + +```javascript +await octokit.request('POST /api/yystopf/ceshi/webhooks/3/test.json') +``` + +### HTTP 请求 +`POST /api/:owner/:repo/webhooks/:id/test.json` + +### 请求参数: +参数 | 必选 | 默认 | 类型 | 字段说明 +--------- | ------- | ------- | -------- | ---------- +|owner |是| | string |用户登录名 | +|repo |是| | string |项目标识identifier | +|id |是| | integer|webhook ID| + + + + +### 返回字段说明: + + +> 返回的JSON示例: + +```json +{ + "status": 0, + "message": "success" +} +``` + \ No newline at end of file diff --git a/app/forms/projects/webhooks/create_form.rb b/app/forms/projects/webhooks/create_form.rb new file mode 100644 index 00000000..75b07b1b --- /dev/null +++ b/app/forms/projects/webhooks/create_form.rb @@ -0,0 +1,8 @@ +class Projects::Webhooks::CreateForm < BaseForm + attr_accessor :type, :url, :http_method, :content_type, :secret, :events, :active, :branch_filter + + 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"} +end \ No newline at end of file diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 226096c2..12a0097b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -13,12 +13,12 @@ module ProjectsHelper end end - def render_zip_url(project, archive_name) - [gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.zip"].join('/') + def render_zip_url(owner, repository, archive) + [base_url, archive_repositories_path(owner&.login, repository, "#{archive}.zip")].join end - def render_tar_url(project, archive_name) - [gitea_domain, project.owner.login, project.identifier, "archive", "#{archive_name}.tar.gz"].join('/') + def render_tar_url(owner, repository, archive) + [base_url, archive_repositories_path(owner&.login, repository, "#{archive}.tar.gz")].join end def render_http_url(project) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index e704acb8..a7218810 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -10,12 +10,12 @@ module RepositoriesHelper end def download_type(str) - default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx dot) + default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb png jpg gif tif psd svg RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2) default_type.include?(str&.downcase) end def image_type?(str) - default_type = %w(png jpg gif tif psd svg) + default_type = %w(png jpg gif tif psd svg gif bmp webp jpeg) default_type.include?(str&.downcase) end @@ -81,9 +81,47 @@ module RepositoriesHelper content = Gitea::Repository::Entries::GetService.call(owner, repo.identifier, entry['path'], ref: ref)['content'] readme_render_decode64_content(content, path) else - file_type = entry['name'].to_s.split(".").last - return entry['content'] if download_type(file_type) + file_type = File.extname(entry['name'].to_s)[1..-1] + if download_type(file_type) + return entry['content'].nil? ? Gitea::Repository::Entries::GetService.call(owner, repo.identifier, entry['path'], ref: ref)['content'] : 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 diff --git a/app/jobs/reset_user_cache_job.rb b/app/jobs/reset_user_cache_job.rb index 3562475c..7b2c5c63 100644 --- a/app/jobs/reset_user_cache_job.rb +++ b/app/jobs/reset_user_cache_job.rb @@ -2,6 +2,7 @@ class ResetUserCacheJob < ApplicationJob queue_as :cache def perform(user) + return if user.nil? Cache::UserFollowCountService.new(user).reset Cache::UserIssueCountService.new(user).reset Cache::UserProjectCountService.new(user).reset diff --git a/app/models/applied_message.rb b/app/models/applied_message.rb index 5c942b7b..01f5fa7e 100644 --- a/app/models/applied_message.rb +++ b/app/models/applied_message.rb @@ -1,19 +1,26 @@ # == Schema Information # -# Table name: applied_messages +# Table name: forge_applied_messages # # id :integer not null, primary key # user_id :integer -# applied_id :integer # applied_type :string(255) +# applied_id :integer # viewed :integer default("0") # status :integer default("0") -# created_at :datetime not null -# updated_at :datetime not null # name :string(255) # applied_user_id :integer # role :integer # project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_forge_applied_messages_on_applied_type_and_applied_id (applied_type,applied_id) +# index_forge_applied_messages_on_applied_user_id (applied_user_id) +# index_forge_applied_messages_on_project_id (project_id) +# index_forge_applied_messages_on_user_id (user_id) # class AppliedMessage < ApplicationRecord diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb index e0b4b6c4..ea7ca6ee 100644 --- a/app/models/applied_project.rb +++ b/app/models/applied_project.rb @@ -1,14 +1,19 @@ # == Schema Information # -# Table name: applied_projects +# Table name: forge_applied_projects # # id :integer not null, primary key -# project_id :integer not null -# user_id :integer not null +# project_id :integer +# user_id :integer # role :integer default("0") # status :integer default("0") -# created_at :datetime -# updated_at :datetime +# created_at :datetime not null +# updated_at :datetime not null +# +# Indexes +# +# index_forge_applied_projects_on_project_id (project_id) +# index_forge_applied_projects_on_user_id (user_id) # class AppliedProject < ApplicationRecord diff --git a/app/models/attachment.rb b/app/models/attachment.rb index c6a50d93..3451246a 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -1,41 +1,42 @@ -# == Schema Information -# -# Table name: attachments -# -# id :integer not null, primary key -# container_id :integer -# container_type :string(30) -# filename :string(255) default(""), not null -# disk_filename :string(255) default(""), not null -# filesize :integer default("0"), not null -# content_type :string(255) default("") -# digest :string(60) default(""), not null -# downloads :integer default("0"), not null -# author_id :integer default("0"), not null -# created_on :datetime -# description :text(65535) -# disk_directory :string(255) -# attachtype :integer default("1") -# is_public :integer default("1") -# copy_from :integer -# quotes :integer default("0") -# is_publish :integer default("1") -# publish_time :datetime -# resource_bank_id :integer -# unified_setting :boolean default("1") -# cloud_url :string(255) default("") -# course_second_category_id :integer default("0") -# delay_publish :boolean default("0") -# -# Indexes -# -# index_attachments_on_author_id (author_id) -# index_attachments_on_container_id_and_container_type (container_id,container_type) -# index_attachments_on_course_second_category_id (course_second_category_id) -# index_attachments_on_created_on (created_on) -# index_attachments_on_is_public (is_public) -# index_attachments_on_quotes (quotes) -# +# == Schema Information +# +# Table name: attachments +# +# id :integer not null, primary key +# container_id :integer +# container_type :string(30) +# filename :string(255) default(""), not null +# disk_filename :string(255) default(""), not null +# filesize :integer default("0"), not null +# content_type :string(255) default("") +# digest :string(60) default(""), not null +# downloads :integer default("0"), not null +# author_id :integer default("0"), not null +# created_on :datetime +# description :text(65535) +# disk_directory :string(255) +# attachtype :integer default("1") +# is_public :integer default("1") +# copy_from :string(255) +# quotes :integer default("0") +# is_publish :integer default("1") +# publish_time :datetime +# resource_bank_id :integer +# unified_setting :boolean default("1") +# cloud_url :string(255) default("") +# course_second_category_id :integer default("0") +# delay_publish :boolean default("0") +# link :string(255) +# clone_id :integer +# +# Indexes +# +# index_attachments_on_author_id (author_id) +# index_attachments_on_clone_id (clone_id) +# index_attachments_on_container_id_and_container_type (container_id,container_type) +# index_attachments_on_created_on (created_on) +# + class Attachment < ApplicationRecord diff --git a/app/models/ci/user.rb b/app/models/ci/user.rb index c263a172..e4a4d062 100644 --- a/app/models/ci/user.rb +++ b/app/models/ci/user.rb @@ -39,17 +39,15 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# platform :string(255) default("0") -# gitea_token :string(255) -# gitea_uid :integer # is_shixun_marker :boolean default("0") +# admin_visitable :boolean default("0") +# collaborator :boolean default("0") +# gitea_uid :integer # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# sponsor_certification :integer default("0") -# sponsor_num :integer default("0") -# sponsored_num :integer default("0") -# award_time :datetime +# gitea_token :string(255) +# platform :string(255) # # Indexes # @@ -57,8 +55,9 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) -# index_users_on_mail (mail) +# index_users_on_login (login) UNIQUE +# index_users_on_mail (mail) UNIQUE +# index_users_on_phone (phone) UNIQUE # index_users_on_type (type) # diff --git a/app/models/concerns/project_operable.rb b/app/models/concerns/project_operable.rb index 79d099a2..a6dc0dd3 100644 --- a/app/models/concerns/project_operable.rb +++ b/app/models/concerns/project_operable.rb @@ -65,7 +65,7 @@ module ProjectOperable if owner.is_a?(User) managers.exists?(user_id: user.id) elsif owner.is_a?(Organization) - managers.exists?(user_id: user.id) || owner.is_only_admin?(user.id) + managers.exists?(user_id: user.id) || owner.is_owner?(user.id) || owner.is_only_admin?(user.id) else false end @@ -94,7 +94,7 @@ module ProjectOperable end def operator?(user) - user.admin? || !reporter?(user) + user.admin? || (member?(user.id) && !reporter?(user)) end def set_developer_role(member, role_name) diff --git a/app/models/gitea/base.rb b/app/models/gitea/base.rb index d14249bf..652fd777 100644 --- a/app/models/gitea/base.rb +++ b/app/models/gitea/base.rb @@ -1,4 +1,6 @@ -class Gitea::Base < Gitea::Database - self.abstract_class = true - +class Gitea::Base < ApplicationRecord + db_config = Rails.configuration.database_configuration[Rails.env]["gitea_server"] + raise 'gitea database config missing' if db_config.blank? + + establish_connection db_config end diff --git a/app/models/gitea/public_key.rb b/app/models/gitea/public_key.rb new file mode 100644 index 00000000..bb219235 --- /dev/null +++ b/app/models/gitea/public_key.rb @@ -0,0 +1,9 @@ +class Gitea::PublicKey < Gitea::Base + self.inheritance_column = nil # FIX The single-table inheritance mechanism failed + # establish_connection :gitea_db + + self.table_name = "public_key" + + belongs_to :user, class_name: '::User', primary_key: :gitea_uid, foreign_key: :owner_id, optional: true + +end diff --git a/app/models/gitea/pull.rb b/app/models/gitea/pull.rb new file mode 100644 index 00000000..7adb8c36 --- /dev/null +++ b/app/models/gitea/pull.rb @@ -0,0 +1,44 @@ +# == Schema Information +# +# Table name: pull_request +# +# id :integer not null, primary key +# type :integer +# status :integer +# conflicted_files :text(65535) +# commits_ahead :integer +# commits_behind :integer +# changed_protected_files :text(65535) +# issue_id :integer +# index :integer +# head_repo_id :integer +# base_repo_id :integer +# head_branch :string(255) +# base_branch :string(255) +# merge_base :string(40) +# has_merged :boolean +# merged_commit_id :string(40) +# merger_id :integer +# merged_unix :integer +# +# Indexes +# +# IDX_pull_request_base_repo_id (base_repo_id) +# IDX_pull_request_has_merged (has_merged) +# IDX_pull_request_head_repo_id (head_repo_id) +# IDX_pull_request_issue_id (issue_id) +# IDX_pull_request_merged_unix (merged_unix) +# IDX_pull_request_merger_id (merger_id) +# + +class Gitea::Pull < Gitea::Base + self.inheritance_column = nil # FIX The single-table inheritance mechanism failed + # establish_connection :gitea_db + + self.table_name = "pull_request" + + serialize :conflicted_files, Array + + belongs_to :pull_request, class_name: '::PullRequest', foreign_key: :id, primary_key: :gitea_id, optional: true + +end diff --git a/app/models/gitea/webhook.rb b/app/models/gitea/webhook.rb new file mode 100644 index 00000000..f60f5678 --- /dev/null +++ b/app/models/gitea/webhook.rb @@ -0,0 +1,13 @@ +class Gitea::Webhook < Gitea::Base + serialize :events, JSON + self.inheritance_column = nil + + self.table_name = 'webhook' + + has_many :tasks, class_name: "Gitea::WebhookTask", foreign_key: :hook_id + belongs_to :project, class_name: "::Project", primary_key: :gpid, foreign_key: :repo_id, optional: true + + enum hook_task_type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9} + enum last_status: {waiting: 0, succeed: 1, fail: 2} + enum content_type: {json: 1, form: 2} +end \ No newline at end of file diff --git a/app/models/gitea/webhook_task.rb b/app/models/gitea/webhook_task.rb new file mode 100644 index 00000000..d19a163a --- /dev/null +++ b/app/models/gitea/webhook_task.rb @@ -0,0 +1,13 @@ +class Gitea::WebhookTask < Gitea::Base + serialize :payload_content, JSON + serialize :request_content, JSON + serialize :response_content, JSON + + self.inheritance_column = nil + + self.table_name = 'hook_task' + + belongs_to :webhook, class_name: "Gitea::Webhook", foreign_key: :hook_id + + enum type: {gogs: 1, slack: 2, gitea: 3, discord: 4, dingtalk: 5, telegram: 6, msteams: 7, feishu: 8, matrix: 9} +end \ No newline at end of file diff --git a/app/models/laboratory.rb b/app/models/laboratory.rb index 699800c9..9d3ca07d 100644 --- a/app/models/laboratory.rb +++ b/app/models/laboratory.rb @@ -10,6 +10,7 @@ # sync_course :boolean default("0") # sync_subject :boolean default("0") # sync_shixun :boolean default("0") +# is_local :boolean default("0") # # Indexes # diff --git a/app/models/license.rb b/app/models/license.rb index dcd5528f..0a14fb85 100644 --- a/app/models/license.rb +++ b/app/models/license.rb @@ -7,7 +7,6 @@ # content :text(65535) # created_at :datetime not null # updated_at :datetime not null -# is_secret :boolean default("0") # class License < ApplicationRecord diff --git a/app/models/member.rb b/app/models/member.rb index 408710a0..e72ae7c6 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -11,7 +11,6 @@ # course_group_id :integer default("0") # is_collect :integer default("1") # graduation_group_id :integer default("0") -# is_apply_signature :boolean default("0") # # Indexes # diff --git a/app/models/organization.rb b/app/models/organization.rb index 666e13ff..843c2b05 100644 --- a/app/models/organization.rb +++ b/app/models/organization.rb @@ -39,17 +39,15 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# platform :string(255) default("0") -# gitea_token :string(255) -# gitea_uid :integer # is_shixun_marker :boolean default("0") +# admin_visitable :boolean default("0") +# collaborator :boolean default("0") +# gitea_uid :integer # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# sponsor_certification :integer default("0") -# sponsor_num :integer default("0") -# sponsored_num :integer default("0") -# award_time :datetime +# gitea_token :string(255) +# platform :string(255) # # Indexes # @@ -57,8 +55,9 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) -# index_users_on_mail (mail) +# index_users_on_login (login) UNIQUE +# index_users_on_mail (mail) UNIQUE +# index_users_on_phone (phone) UNIQUE # index_users_on_type (type) # diff --git a/app/models/project.rb b/app/models/project.rb index eb8a0bbf..414f5b55 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,79 +1,79 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) default(""), not null -# description :text(4294967295) -# homepage :string(255) default("") -# is_public :boolean default("1"), not null -# parent_id :integer -# created_on :datetime -# updated_on :datetime -# identifier :string(255) -# status :integer default("1"), not null -# lft :integer -# rgt :integer -# inherit_members :boolean default("0"), not null -# project_type :integer default("0") -# hidden_repo :boolean default("0"), not null -# attachmenttype :integer default("1") -# user_id :integer -# dts_test :integer default("0") -# enterprise_name :string(255) -# organization_id :integer -# project_new_type :integer -# gpid :integer -# forked_from_project_id :integer -# forked_count :integer default("0") -# publish_resource :integer default("0") -# visits :integer default("0") -# hot :integer default("0") -# invite_code :string(255) -# qrcode :string(255) -# qrcode_expiretime :integer default("0") -# script :text(65535) -# training_status :integer default("0") -# rep_identifier :string(255) -# project_category_id :integer -# project_language_id :integer -# license_id :integer -# ignore_id :integer -# praises_count :integer default("0") -# watchers_count :integer default("0") -# issues_count :integer default("0") -# pull_requests_count :integer default("0") -# language :string(255) -# versions_count :integer default("0") -# issue_tags_count :integer default("0") -# closed_issues_count :integer default("0") -# open_devops :boolean default("0") -# gitea_webhook_id :integer -# open_devops_count :integer default("0") -# recommend :boolean default("0") -# platform :integer default("0") -# default_branch :string(255) default("master") -# website :string(255) -# order_index :integer default("0") -# lesson_url :string(255) -# -# Indexes -# -# index_projects_on_forked_from_project_id (forked_from_project_id) -# index_projects_on_identifier (identifier) -# index_projects_on_invite_code (invite_code) -# index_projects_on_is_public (is_public) -# index_projects_on_lft (lft) -# index_projects_on_name (name) -# index_projects_on_platform (platform) -# index_projects_on_project_type (project_type) -# index_projects_on_recommend (recommend) -# index_projects_on_rgt (rgt) -# index_projects_on_status (status) -# index_projects_on_updated_on (updated_on) -# - - +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) default(""), not null +# description :text(4294967295) +# homepage :string(255) default("") +# is_public :boolean default("1"), not null +# parent_id :integer +# created_on :datetime +# updated_on :datetime +# identifier :string(255) +# status :integer default("1"), not null +# lft :integer +# rgt :integer +# inherit_members :boolean default("0"), not null +# project_type :integer default("0") +# hidden_repo :boolean default("0"), not null +# attachmenttype :integer default("1") +# user_id :integer +# dts_test :integer default("0") +# enterprise_name :string(255) +# organization_id :integer +# project_new_type :integer +# gpid :integer +# forked_from_project_id :integer +# forked_count :integer default("0") +# publish_resource :integer default("0") +# visits :integer default("0") +# hot :integer default("0") +# invite_code :string(255) +# qrcode :string(255) +# qrcode_expiretime :integer default("0") +# script :text(65535) +# training_status :integer default("0") +# rep_identifier :string(255) +# project_category_id :integer +# project_language_id :integer +# praises_count :integer default("0") +# watchers_count :integer default("0") +# issues_count :integer default("0") +# pull_requests_count :integer default("0") +# language :string(255) +# versions_count :integer default("0") +# issue_tags_count :integer default("0") +# closed_issues_count :integer default("0") +# open_devops :boolean default("0") +# gitea_webhook_id :integer +# open_devops_count :integer default("0") +# recommend :boolean default("0") +# platform :integer default("0") +# license_id :integer +# ignore_id :integer +# default_branch :string(255) default("master") +# website :string(255) +# lesson_url :string(255) +# +# Indexes +# +# index_projects_on_forked_from_project_id (forked_from_project_id) +# index_projects_on_identifier (identifier) +# index_projects_on_invite_code (invite_code) +# index_projects_on_is_public (is_public) +# index_projects_on_lft (lft) +# index_projects_on_license_id (license_id) +# index_projects_on_name (name) +# index_projects_on_platform (platform) +# index_projects_on_project_category_id (project_category_id) +# index_projects_on_project_language_id (project_language_id) +# index_projects_on_project_type (project_type) +# index_projects_on_recommend (recommend) +# index_projects_on_rgt (rgt) +# index_projects_on_status (status) +# index_projects_on_updated_on (updated_on) +# class Project < ApplicationRecord @@ -98,10 +98,12 @@ class Project < ApplicationRecord belongs_to :organization_extension, foreign_key: :user_id, primary_key: :organization_id, optional: true, counter_cache: :num_projects belongs_to :project_category, optional: true , :counter_cache => true belongs_to :project_language, optional: true , :counter_cache => true + belongs_to :forked_from_project, class_name: 'Project', optional: true, foreign_key: :forked_from_project_id has_many :project_trends, dependent: :destroy has_many :watchers, as: :watchable, dependent: :destroy has_many :fork_users, dependent: :destroy has_many :forked_users, class_name: 'ForkUser', foreign_key: :fork_project_id, dependent: :destroy + has_many :forked_projects, class_name: 'Project', foreign_key: :forked_from_project_id has_one :project_educoder, dependent: :destroy has_one :project_score, dependent: :destroy @@ -120,6 +122,7 @@ class Project < ApplicationRecord has_one :applied_transfer_project,-> { order created_at: :desc }, dependent: :destroy has_many :pinned_projects, dependent: :destroy has_many :has_pinned_users, through: :pinned_projects, source: :user + has_many :webhooks, class_name: "Gitea::Webhook", primary_key: :gpid, foreign_key: :repo_id after_save :check_project_members, :reset_cache_data before_save :set_invite_code diff --git a/app/models/project_category.rb b/app/models/project_category.rb index 3a981981..67b80299 100644 --- a/app/models/project_category.rb +++ b/app/models/project_category.rb @@ -8,11 +8,6 @@ # projects_count :integer default("0") # created_at :datetime not null # updated_at :datetime not null -# ancestry :string(255) -# -# Indexes -# -# index_project_categories_on_ancestry (ancestry) # class ProjectCategory < ApplicationRecord diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index 4226d561..aec32085 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -37,6 +37,7 @@ class PullRequest < ApplicationRecord has_many :pull_request_tags, foreign_key: :pull_request_id has_many :project_trends, as: :trend, dependent: :destroy has_many :attachments, as: :container, dependent: :destroy + has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_id, class_name: 'Gitea::Pull' scope :merged_and_closed, ->{where.not(status: 0)} scope :opening, -> {where(status: 0)} @@ -53,8 +54,10 @@ class PullRequest < ApplicationRecord Project.find_by(id: self.fork_project_id) end - def bind_gitea_pull_request!(gitea_pull_number) - update_column(:gpid, gitea_pull_number) + def bind_gitea_pull_request!(gitea_pull_number, gitea_pull_id) + update_columns( + gitea_number: gitea_pull_number, + gitea_id: gitea_pull_id) end def merge! @@ -67,19 +70,26 @@ class PullRequest < ApplicationRecord # TODO: sync educoder platform repo's for update some statistics count def self.update_some_count - PullRequest.includes(:user, :project).select(:id, :user_id, :gpid, :project_id, :fork_project_id).each do |pr| + PullRequest.includes(:user, :project).select(:id, :user_id, :gitea_number, :project_id, :fork_project_id).each do |pr| puts pr.id - next if pr.gpid.blank? + next if pr.gitea_number.blank? project = pr.project next if project.blank? user = project.owner - next if pr.gpid === 6 || pr.gpid === 7 - files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gpid) + next if pr.gitea_number === 6 || pr.gitea_number === 7 + files_result = Gitea::PullRequest::FilesService.call(user.login, project.identifier, pr.gitea_number) pr.update_column(:files_count, files_result['NumFiles']) unless files_result.blank? - commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gpid) + commits_result = Gitea::PullRequest::CommitsService.call(user.login, project.identifier, pr.gitea_number) pr.update_column(:commits_count, commits_result.size) unless commits_result.blank? end end + + def conflict_files + file_names = self&.gitea_pull&.conflicted_files + return [] if file_names.blank? + + JSON.parse file_names + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index cefdf6ea..a012b449 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -27,7 +27,6 @@ # # Indexes # -# index_repositories_on_identifier (identifier) # index_repositories_on_project_id (project_id) # index_repositories_on_user_id (user_id) # diff --git a/app/models/user.rb b/app/models/user.rb index 0b5b1079..c2a21425 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -39,17 +39,15 @@ # business :boolean default("0") # profile_completed :boolean default("0") # laboratory_id :integer -# platform :string(255) default("0") -# gitea_token :string(255) -# gitea_uid :integer # is_shixun_marker :boolean default("0") +# admin_visitable :boolean default("0") +# collaborator :boolean default("0") +# gitea_uid :integer # is_sync_pwd :boolean default("1") # watchers_count :integer default("0") # devops_step :integer default("0") -# sponsor_certification :integer default("0") -# sponsor_num :integer default("0") -# sponsored_num :integer default("0") -# award_time :datetime +# gitea_token :string(255) +# platform :string(255) # # Indexes # @@ -57,8 +55,9 @@ # index_users_on_homepage_engineer (homepage_engineer) # index_users_on_homepage_teacher (homepage_teacher) # index_users_on_laboratory_id (laboratory_id) -# index_users_on_login (login) -# index_users_on_mail (mail) +# index_users_on_login (login) UNIQUE +# index_users_on_mail (mail) UNIQUE +# index_users_on_phone (phone) UNIQUE # index_users_on_type (type) # @@ -171,6 +170,7 @@ class User < Owner accepts_nested_attributes_for :is_pinned_projects has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :pull_requests, dependent: :destroy + has_many :public_keys, class_name: "Gitea::PublicKey",primary_key: :gitea_uid, foreign_key: :owner_id, dependent: :destroy # Groups and active users scope :active, lambda { where(status: [STATUS_ACTIVE, STATUS_EDIT_INFO]) } @@ -187,7 +187,7 @@ class User < Owner :show_email, :show_location, :show_department, :technical_title, :province, :city, :custom_department, to: :user_extension, allow_nil: true - before_save :update_hashed_password + before_save :update_hashed_password, :set_lastname after_create do SyncTrustieJob.perform_later("user", 1) if allow_sync_to_trustie? end @@ -792,6 +792,10 @@ class User < Owner self.laboratory = Laboratory.current if laboratory_id.blank? end + + def set_lastname + self.lastname = self.nickname if changes[:nickname].present? + end end diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 3ad8010e..17935969 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -12,7 +12,9 @@ # # Indexes # -# index_user_actions_on_ip (ip) +# index_user_actions_on_ip (ip) +# index_user_actions_on_user_id (user_id) +# index_user_actions_on_user_id_and_action_type (user_id,action_type) # class UserAction < ApplicationRecord diff --git a/app/models/user_agent.rb b/app/models/user_agent.rb index 49d7b35a..ba519d6f 100644 --- a/app/models/user_agent.rb +++ b/app/models/user_agent.rb @@ -10,10 +10,13 @@ # updated_at :datetime not null # register_status :integer default("0") # action_status :integer default("0") +# is_delete :boolean default("0") +# user_id :integer # # Indexes # -# index_user_agents_on_ip (ip) UNIQUE +# index_user_agents_on_ip (ip) +# index_user_agents_on_user_id (user_id) # class UserAgent < ApplicationRecord diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 0749d1f7..ee208af7 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -22,6 +22,9 @@ # school_id :integer # description :string(255) default("") # department_id :integer +# honor :text(65535) +# edu_background :integer +# edu_entry_year :integer # province :string(255) # city :string(255) # custom_department :string(255) diff --git a/app/services/cache/platform_project_languages_count_service.rb b/app/services/cache/platform_project_languages_count_service.rb index 2b4f0fae..0c6ffab1 100644 --- a/app/services/cache/platform_project_languages_count_service.rb +++ b/app/services/cache/platform_project_languages_count_service.rb @@ -46,11 +46,11 @@ class Cache::PlatformProjectLanguagesCountService < ApplicationService def reset_platform_project_language_count_by_key return if key.nil? - $redis_cache.hset(platform_project_language_count_key, key, Project.joins(:project_language).where(project_languages: {name: key}).count) + $redis_cache.hset(platform_project_language_count_key, key, ProjectLanguage.where(name: key).projects_count) end def reset_platform_project_language_count - Project.joins(:project_language).group("project_languages.name").count.each do |k, v| + ProjectLanguage.where.not(projects_count: 0).group("project_languages.name").sum(:projects_count).each do |k, v| $redis_cache.hset(platform_project_language_count_key, k, v) end end diff --git a/app/services/gitea/client_service.rb b/app/services/gitea/client_service.rb index b88d8382..868a704c 100644 --- a/app/services/gitea/client_service.rb +++ b/app/services/gitea/client_service.rb @@ -108,6 +108,7 @@ class Gitea::ClientService < ApplicationService def full_url(api_rest, action='post') url = [api_url, api_rest].join('').freeze url = action === 'get' ? url : URI.escape(url) + url = URI.escape(url) unless url.ascii_only? puts "[gitea] request url: #{url}" return url end diff --git a/app/services/gitea/pull_request/close_service.rb b/app/services/gitea/pull_request/close_service.rb index aed5251b..3ca062e6 100644 --- a/app/services/gitea/pull_request/close_service.rb +++ b/app/services/gitea/pull_request/close_service.rb @@ -8,7 +8,7 @@ class Gitea::PullRequest::CloseService < Gitea::PullRequest::UpdateService # number: number of pull request # token: token of gitea user # eq: - # Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gpid, pull.base, current_user.gitea_token) + # Gitea::PullRequest::CloseService.call(owner.login, repo.identifier, pull.gitea_number, pull.base, current_user.gitea_token) def initialize(owner, repo, number, base,token=nil) colse_pull_params = Hash.new.merge(base: base, state: 'closed').compact diff --git a/app/services/gitea/pull_request/get_service.rb b/app/services/gitea/pull_request/get_service.rb index 601c669e..f9a35fdc 100644 --- a/app/services/gitea/pull_request/get_service.rb +++ b/app/services/gitea/pull_request/get_service.rb @@ -3,7 +3,7 @@ class Gitea::PullRequest::GetService < Gitea::ClientService attr_reader :owner, :repo, :number, :token #eq: - # Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gpid, user.gitea_token) + # Gitea::PullRequest::GetService.call(user.login, repository.identifier, pull.gitea_number, user.gitea_token) def initialize(owner, repo, number, token=nil) @owner = owner @repo = repo diff --git a/app/services/gitea/pull_request/open_service.rb b/app/services/gitea/pull_request/open_service.rb index affdfe11..4d2137f1 100644 --- a/app/services/gitea/pull_request/open_service.rb +++ b/app/services/gitea/pull_request/open_service.rb @@ -8,7 +8,7 @@ class Gitea::PullRequest::OpenService < Gitea::PullRequest::UpdateService # number: number of pull request # token: token of gitea user # eq: - # Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gpid, pr.base, current_user.gitea_token) + # Gitea::PullRequest::OpenService.new(owner.login, repo.identifier, pr.gitea_number, pr.base, current_user.gitea_token) def initialize(owner, repo, number, base, token=nil) open_pull_params = Hash.new.merge(base: base, state: 'open').compact diff --git a/app/services/gitea/repository/archive_service.rb b/app/services/gitea/repository/archive_service.rb new file mode 100644 index 00000000..1b5e1e2a --- /dev/null +++ b/app/services/gitea/repository/archive_service.rb @@ -0,0 +1,40 @@ +class Gitea::Repository::ArchiveService < Gitea::ClientService + attr_reader :owner, :repo, :archive, :token + + def initialize(owner, repo, archive, token=nil) + @owner = owner + @repo = repo + @archive = archive + @token = token + end + + def call + response = get(url, params) + response_payload(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/archive/#{archive}".freeze + end + + def response_payload(response) + status = response.status + body = response&.body + + log_error(status, body) + status_payload(status, body) + end + + def status_payload(status, body) + case status + when 200 then success + when 404 then error("你操作的链接不存在!") + else error("系统错误!") + end + end +end diff --git a/app/services/gitea/repository/webhooks/create_service.rb b/app/services/gitea/repository/webhooks/create_service.rb new file mode 100644 index 00000000..33c9a9b0 --- /dev/null +++ b/app/services/gitea/repository/webhooks/create_service.rb @@ -0,0 +1,23 @@ +class Gitea::Repository::Webhooks::CreateService < Gitea::ClientService + attr_reader :token, :owner, :repo, :params + def initialize(token, owner, repo, params) + @token = token + @owner = owner + @repo = repo + @params = params + end + + def call + response = post(url, request_params) + render_response(response) + end + + private + def request_params + Hash.new.merge({token: token, data: params}) + end + + def url + "/repos/#{owner}/#{repo}/hooks".freeze + end +end \ No newline at end of file diff --git a/app/services/gitea/repository/webhooks/delete_service.rb b/app/services/gitea/repository/webhooks/delete_service.rb new file mode 100644 index 00000000..997e9006 --- /dev/null +++ b/app/services/gitea/repository/webhooks/delete_service.rb @@ -0,0 +1,24 @@ +class Gitea::Repository::Webhooks::DeleteService < Gitea::ClientService + attr_reader :token, :owner, :repo, :id + + def initialize(token, owner, repo, id) + @token = token + @owner = owner + @repo = repo + @id = id + end + + def call + response = delete(url, params) + render_response(response) + end + + private + def params + Hash.new.merge(token: token) + end + + def url + "/repos/#{owner}/#{repo}/hooks/#{id}".freeze + end +end \ No newline at end of file diff --git a/app/services/gitea/repository/webhooks/tasks_service.rb b/app/services/gitea/repository/webhooks/tasks_service.rb new file mode 100644 index 00000000..e4c62edb --- /dev/null +++ b/app/services/gitea/repository/webhooks/tasks_service.rb @@ -0,0 +1,27 @@ +class Gitea::Repository::Webhooks::TasksService < Gitea::ClientService + attr_reader :token, :owner, :repo, :webhook_id + + # ref: The name of the commit/branch/tag. Default the repository’s default branch (usually master) + # repo_name: the name of repository + def initialize(token, owner, repo, webhook_id) + @token = token + @owner = owner + @repo = repo + @webhook_id = webhook_id + end + + def call + response = get(url, params) + render_response(response) + end + + private + def params + Hash.new.merge(token: user.gitea_token) + end + + def url + "/repos/#{owner}/#{repo}/hooks/#{webhook_id}/hook_tasks".freeze + end + +end diff --git a/app/services/gitea/repository/webhooks/test_service.rb b/app/services/gitea/repository/webhooks/test_service.rb new file mode 100644 index 00000000..7f183761 --- /dev/null +++ b/app/services/gitea/repository/webhooks/test_service.rb @@ -0,0 +1,24 @@ +class Gitea::Repository::Webhooks::TestService < Gitea::ClientService + attr_reader :token, :owner, :repo, :webhook_id + + def initialize(token, owner, repo, webhook_id) + @token = token + @owner = owner + @repo = repo + @webhook_id = webhook_id + end + + def call + response = post(url, request_params) + render_response(response) + end + + private + def request_params + Hash.new.merge({token: token}) + end + + def url + "/repos/#{owner}/#{repo}/hooks/#{webhook_id}/tests".freeze + end +end \ No newline at end of file diff --git a/app/services/gitea/repository/webhooks/update_service.rb b/app/services/gitea/repository/webhooks/update_service.rb new file mode 100644 index 00000000..6094c6c5 --- /dev/null +++ b/app/services/gitea/repository/webhooks/update_service.rb @@ -0,0 +1,24 @@ +class Gitea::Repository::Webhooks::UpdateService < Gitea::ClientService + attr_reader :token, :owner, :repo, :id, :params + def initialize(token, owner, repo, id, params) + @token = token + @owner = owner + @repo = repo + @id = id + @params = params + end + + def call + response = patch(url, data_params) + render_response(response) + end + + private + def url + "/repos/#{owner}/#{repo}/hooks/#{id}" + end + + def data_params + Hash.new.merge(token: token, data: params).compact + end +end \ No newline at end of file diff --git a/app/services/gitea/user/keys/create_service.rb b/app/services/gitea/user/keys/create_service.rb new file mode 100644 index 00000000..2b720c48 --- /dev/null +++ b/app/services/gitea/user/keys/create_service.rb @@ -0,0 +1,21 @@ +class Gitea::User::Keys::CreateService < Gitea::ClientService + attr_reader :token, :params + def initialize(token, params) + @token = token + @params = params + end + + def call + response = post(url, request_params) + render_response(response) + end + + private + def request_params + Hash.new.merge({token: token, data: params}) + end + + def url + '/user/keys'.freeze + end +end \ No newline at end of file diff --git a/app/services/gitea/user/keys/delete_service.rb b/app/services/gitea/user/keys/delete_service.rb new file mode 100644 index 00000000..3ae263e3 --- /dev/null +++ b/app/services/gitea/user/keys/delete_service.rb @@ -0,0 +1,23 @@ +class Gitea::User::Keys::DeleteService < Gitea::ClientService + attr_reader :token, :key_id + + def initialize(token, key_id) + @token = token + @key_id = key_id + end + + def call + response = delete(url, params) + render_response(response) + end + + private + + def params + Hash.new.merge(token: token) + end + + def url + "/user/keys/#{key_id}".freeze + end +end diff --git a/app/services/gitea/user/keys/get_service.rb b/app/services/gitea/user/keys/get_service.rb new file mode 100644 index 00000000..fbcf1c86 --- /dev/null +++ b/app/services/gitea/user/keys/get_service.rb @@ -0,0 +1,22 @@ +class Gitea::User::Keys::GetService < Gitea::ClientService + attr_reader :token, :key_id + + def initialize(token, key_id) + @token = token + @key_id = key_id + end + + def call + response = get(url, params) + render_response(response) + end + + private + def params + Hash.new.merge({token: token}) + end + + def url + "/user/keys/#{key_id}".freeze + end +end \ No newline at end of file diff --git a/app/services/gitea/user/keys/list_service.rb b/app/services/gitea/user/keys/list_service.rb new file mode 100644 index 00000000..1ddfde41 --- /dev/null +++ b/app/services/gitea/user/keys/list_service.rb @@ -0,0 +1,26 @@ +class Gitea::User::Keys::ListService < Gitea::ClientService + attr_reader :token, :page, :limit, :fingerprint + + def initialize(token, page, limit, fingerprint="") + @token = token + @page = page + @limit = limit + @fingerprint = fingerprint + end + + def call + response = get(url, params) + render_response(response) + end + + private + + def params + Hash.new.merge({token: token, fingerprint: fingerprint, page: page, limit: limit}) + end + + def url + '/user/keys'.freeze + end + +end \ No newline at end of file diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index f014b8d7..e7e4924a 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -8,6 +8,7 @@ class Projects::CreateService < ApplicationService def call Rails.logger.info("#############__________project_params______###########{project_params}") + raise Error, "user_id不正确." unless authroize_user_id_success @project = Project.new(project_params) ActiveRecord::Base.transaction do @@ -27,6 +28,10 @@ class Projects::CreateService < ApplicationService private + def authroize_user_id_success + (user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?) + end + def project_params { name: params[:name], diff --git a/app/services/projects/migrate_service.rb b/app/services/projects/migrate_service.rb index 7df08f9e..68ed9f64 100644 --- a/app/services/projects/migrate_service.rb +++ b/app/services/projects/migrate_service.rb @@ -8,6 +8,8 @@ class Projects::MigrateService < ApplicationService end def call + raise Error, "user_id不正确." unless authroize_user_id_success + @project = Project.new(project_params) if @project.save! ProjectUnit.init_types(@project.id, project.project_type) @@ -24,6 +26,9 @@ class Projects::MigrateService < ApplicationService end private + def authroize_user_id_success + (user.id == params[:user_id].to_i) || (user.organizations.find_by_id(params[:user_id]).present?) + end def project_params { diff --git a/app/services/pull_requests/close_service.rb b/app/services/pull_requests/close_service.rb index e0ac19b4..60a0ab13 100644 --- a/app/services/pull_requests/close_service.rb +++ b/app/services/pull_requests/close_service.rb @@ -23,7 +23,7 @@ class PullRequests::CloseService < ApplicationService def close_gitea_pull Gitea::PullRequest::CloseService.call(@owner.login, @repo.identifier, - @pull.gpid, @pull.base, current_user.gitea_token) + @pull.gitea_number, @pull.base, current_user.gitea_token) end def update_pull_status! diff --git a/app/services/pull_requests/merge_service.rb b/app/services/pull_requests/merge_service.rb index d5fc102e..46341212 100644 --- a/app/services/pull_requests/merge_service.rb +++ b/app/services/pull_requests/merge_service.rb @@ -22,7 +22,7 @@ class PullRequests::MergeService < ApplicationService def gitea_pull_merge! result = Gitea::PullRequest::MergeService.call(@current_user.gitea_token, @owner.login, - @repo.identifier, @pull.gpid, gitea_merge_pull_params) + @repo.identifier, @pull.gitea_number, gitea_merge_pull_params) @status, @message = result end diff --git a/app/services/pull_requests/open_service.rb b/app/services/pull_requests/open_service.rb index 3081e52b..490071c0 100644 --- a/app/services/pull_requests/open_service.rb +++ b/app/services/pull_requests/open_service.rb @@ -23,7 +23,7 @@ class PullRequests::OpenService < ApplicationService def open_gitea_pull Gitea::PullRequest::OpenService.call(@owner.login, @repo.identifier, - @pull.gpid, @pull.base, @current_user.gitea_token) + @pull.gitea_number, @pull.base, @current_user.gitea_token) end def update_pull_status! diff --git a/app/views/compare/show.json.jbuilder b/app/views/compare/show.json.jbuilder index 8b75fa3d..0037d8be 100644 --- a/app/views/compare/show.json.jbuilder +++ b/app/views/compare/show.json.jbuilder @@ -83,3 +83,5 @@ json.diff do end end +json.status @merge_status +json.message @merge_message \ No newline at end of file diff --git a/app/views/owners/index.json.jbuilder b/app/views/owners/index.json.jbuilder index 677aff71..6b7e5222 100644 --- a/app/views/owners/index.json.jbuilder +++ b/app/views/owners/index.json.jbuilder @@ -2,6 +2,6 @@ json.total_count @owners.size json.owners @owners.each do |owner| json.id owner.id json.type owner.type - json.name owner.login + json.name owner&.show_real_name json.avatar_url url_to_avatar(owner) end \ No newline at end of file diff --git a/app/views/projects/branches.json.jbuilder b/app/views/projects/branches.json.jbuilder index d6f45137..dd722c9d 100644 --- a/app/views/projects/branches.json.jbuilder +++ b/app/views/projects/branches.json.jbuilder @@ -4,8 +4,8 @@ json.array! @branches do |branch| json.user_can_merge branch['user_can_merge'] json.protected branch['protected'] json.http_url render_http_url(@project) - json.zip_url render_zip_url(@project, branch['name']) - json.tar_url render_tar_url(@project, branch['name']) + json.zip_url render_zip_url(@owner, @repository, branch['name']) + json.tar_url render_tar_url(@owner, @repository, branch['name']) json.last_commit do json.sha branch['commit']['id'] json.message branch['commit']['message'] diff --git a/app/views/projects/create.json.jbuilder b/app/views/projects/create.json.jbuilder index 0a586a65..4b4c63fe 100644 --- a/app/views/projects/create.json.jbuilder +++ b/app/views/projects/create.json.jbuilder @@ -1 +1,2 @@ json.extract! @project, :id, :name,:identifier +json.login @project&.owner.login diff --git a/app/views/projects/webhooks/_detail.json.jbuilder b/app/views/projects/webhooks/_detail.json.jbuilder new file mode 100644 index 00000000..2497e5c6 --- /dev/null +++ b/app/views/projects/webhooks/_detail.json.jbuilder @@ -0,0 +1,4 @@ +json.(webhook, :id, :url, :http_method, :is_active) +json.type webhook.hook_task_type +json.last_status webhook.last_status +json.create_time Time.at(webhook.created_unix).strftime("%Y-%m-%d %H:%M:%S") \ No newline at end of file diff --git a/app/views/projects/webhooks/create.json.jbuilder b/app/views/projects/webhooks/create.json.jbuilder new file mode 100644 index 00000000..6d6dde31 --- /dev/null +++ b/app/views/projects/webhooks/create.json.jbuilder @@ -0,0 +1,7 @@ +json.id @webhook["id"] +json.type @webhook["type"] +json.content_type @webhook["config"]["content_type"] +json.url @webhook["config"]["url"] +json.events @webhook["events"] +json.active @webhook["active"] +json.create_time @webhook["created_at"].to_time.strftime("%Y-%m-%d %H:%M:%S") \ No newline at end of file diff --git a/app/views/projects/webhooks/edit.json.jbuilder b/app/views/projects/webhooks/edit.json.jbuilder new file mode 100644 index 00000000..2ee6d24e --- /dev/null +++ b/app/views/projects/webhooks/edit.json.jbuilder @@ -0,0 +1,11 @@ +json.id @webhook.id +json.(@webhook, :id, :http_method, :content_type, :url, :secret, :last_status, :is_active) +json.type @webhook.hook_task_type +json.create_time Time.at(@webhook.created_unix).strftime("%Y-%m-%d %H:%M:%S") +event = @webhook.events +json.branch_filter event["branch_filter"] +if event["send_everything"] + json.events event["events"].keys.collect{|i| i == "pull_request" ? i + "_only" : i} +else + json.events event["events"].select{|k, v| v}.keys.collect{|i| i == "pull_request" ? i + "_only" : i} +end diff --git a/app/views/projects/webhooks/index.json.jbuilder b/app/views/projects/webhooks/index.json.jbuilder new file mode 100644 index 00000000..62722acb --- /dev/null +++ b/app/views/projects/webhooks/index.json.jbuilder @@ -0,0 +1,4 @@ +json.total_count @webhooks.total_count +json.webhooks @webhooks.each do |webhook| + json.partial! 'detail', webhook: webhook +end \ No newline at end of file diff --git a/app/views/projects/webhooks/tasks.json.jbuilder b/app/views/projects/webhooks/tasks.json.jbuilder new file mode 100644 index 00000000..b8aef99f --- /dev/null +++ b/app/views/projects/webhooks/tasks.json.jbuilder @@ -0,0 +1,5 @@ +json.total_count @tasks.total_count +json.tasks @tasks.each do |task| + json.(task, :id, :type, :uuid, :is_succeed, :is_delivered, :payload_content, :request_content, :response_content) + json.delivered_time Time.at(task.delivered*10**-9).strftime("%Y-%m-%d %H:%M:%S") +end \ No newline at end of file diff --git a/app/views/public_keys/create.json.jbuilder b/app/views/public_keys/create.json.jbuilder new file mode 100644 index 00000000..9296413a --- /dev/null +++ b/app/views/public_keys/create.json.jbuilder @@ -0,0 +1,8 @@ +if @public_key.present? + json.status 0 + json.id @public_key["id"] + json.name @public_key["title"] + json.content @public_key["key"] + json.fingerprint @public_key["fingerprint"] + json.created_time @public_key["created_at"].to_time.strftime("%Y/%m/%d %H:%M") +end \ No newline at end of file diff --git a/app/views/public_keys/index.json.jbuilder b/app/views/public_keys/index.json.jbuilder new file mode 100644 index 00000000..6710529b --- /dev/null +++ b/app/views/public_keys/index.json.jbuilder @@ -0,0 +1,5 @@ +json.total_count @public_keys.total_count +json.public_keys @public_keys do |public_key| + json.(public_key, :id, :name, :content, :fingerprint, :created_unix) + json.created_time Time.at(public_key.created_unix).strftime("%Y/%m/%d %H:%M") +end \ No newline at end of file diff --git a/app/views/pull_requests/show.json.jbuilder b/app/views/pull_requests/show.json.jbuilder index 9c268186..6f634390 100644 --- a/app/views/pull_requests/show.json.jbuilder +++ b/app/views/pull_requests/show.json.jbuilder @@ -32,3 +32,5 @@ json.issue do json.version @issue.version.try(:name) json.issue_tags @issue.get_issue_tags end + +json.conflict_files @pull_request.conflict_files diff --git a/app/views/repositories/_simple_entry.json.jbuilder b/app/views/repositories/_simple_entry.json.jbuilder index ec2a045b..6c208875 100644 --- a/app/views/repositories/_simple_entry.json.jbuilder +++ b/app/views/repositories/_simple_entry.json.jbuilder @@ -1,6 +1,6 @@ if @project.forge? file_name = entry['name'] - file_type = file_name.to_s.split(".").last + file_type = File.extname(file_name.to_s)[1..-1] direct_download = download_type(file_type) image_type = image_type?(file_type) json.name file_name @@ -11,7 +11,16 @@ if @project.forge? json.content decode64_content(entry, @owner, @repository, @ref) json.target entry['target'] - json.download_url entry['download_url'] + + download_url = + if image_type + dir_path = [@owner.login, @repository.identifier, "raw/branch", @ref].join('/') + render_download_image_url(dir_path, entry['path'], decode64_content(entry, @owner, @repository, @ref)) + else + entry['download_url'] + end + json.download_url download_url + json.direct_download direct_download json.image_type image_type json.is_readme_file is_readme?(entry['type'], entry['name']) diff --git a/app/views/repositories/entries.json.jbuilder b/app/views/repositories/entries.json.jbuilder index a12c088b..8c028e6a 100644 --- a/app/views/repositories/entries.json.jbuilder +++ b/app/views/repositories/entries.json.jbuilder @@ -42,8 +42,9 @@ if @project.forge? #json.tags_count @tags_count #json.branches_count @branches_count json.commits_count @commits_count - json.zip_url render_zip_url(@project, @ref) - json.tar_url render_tar_url(@project, @ref) + # json.zip_url archive_repositories_path(@owner&.login, @repository, @ref) + json.zip_url render_zip_url(@owner, @repository, @ref) + json.tar_url render_tar_url(@owner, @repository, @ref) json.entries do json.array! @entries do |entry| json.name entry['name'] diff --git a/app/views/repositories/tags.json.jbuilder b/app/views/repositories/tags.json.jbuilder index 23dae426..9db3ff93 100644 --- a/app/views/repositories/tags.json.jbuilder +++ b/app/views/repositories/tags.json.jbuilder @@ -2,8 +2,8 @@ json.array! @tags do |tag| if tag.present? json.name tag['name'] json.id tag['id'] - json.zipball_url tag['zipball_url'] - json.tarball_url tag['tarball_url'] + json.zipball_url render_zip_url(@owner, @repository, tag['name']) + json.tarball_url render_tar_url(@owner, @repository, tag['name']) json.commit do json.sha tag['commit']['sha'] end diff --git a/app/views/version_releases/index.json.jbuilder b/app/views/version_releases/index.json.jbuilder index f1730ffa..88ae36f2 100644 --- a/app/views/version_releases/index.json.jbuilder +++ b/app/views/version_releases/index.json.jbuilder @@ -14,8 +14,8 @@ json.releases do json.name re["name"] json.body re["body"] json.url re["url"] - json.tarball_url re["tarball_url"] - json.zipball_url re["zipball_url"] + json.tarball_url render_tar_url(@owner, @repository, re["tag_name"]) + json.zipball_url render_zip_url(@owner, @repository, re["tag_name"]) json.draft re["draft"] ? "草稿" : (re["prerelease"] ? "预发行" : "稳定") json.created_at format_time(version.created_at.to_s.to_time) json.published_at format_time(version.created_at.to_s.to_time) @@ -30,8 +30,8 @@ json.releases do json.name re["name"] json.body re["body"] json.url re["url"] - json.tarball_url re["tarball_url"] - json.zipball_url re["zipball_url"] + json.tarball_url render_tar_url(@owner, @repository, re["tag_name"]) + json.zipball_url render_zip_url(@owner, @repository, re["tag_name"]) json.draft re["draft"] ? "草稿" : (re["prerelease"] ? "预发行" : "稳定") json.created_at format_time(version.created_at.to_s.to_time) json.published_at format_time(version.created_at.to_s.to_time) diff --git a/app/views/versions/index.json.jbuilder b/app/views/versions/index.json.jbuilder index 044d4c5f..4c15d45e 100644 --- a/app/views/versions/index.json.jbuilder +++ b/app/views/versions/index.json.jbuilder @@ -7,8 +7,8 @@ json.versions do json.array! @versions.each.to_a do |version| json.extract! version, :id, :name, :description, :effective_date,:status,:percent - json.open_issues_count (version.issues_count - version.closed_issues_count) - json.close_issues_count version.closed_issues_count + json.open_issues_count (version.issues.issue_issue.size - version.issues.issue_issue.closed.size) + json.close_issues_count version.issues.issue_issue.closed.size json.created_at format_time(version.created_on) json.updated_at format_time(version.updated_on) json.user_name version.version_user.try(:show_real_name) diff --git a/app/views/versions/show.json.jbuilder b/app/views/versions/show.json.jbuilder index 23f4fbb9..fe8606b2 100644 --- a/app/views/versions/show.json.jbuilder +++ b/app/views/versions/show.json.jbuilder @@ -1,7 +1,7 @@ json.partial! "commons/success" -json.issues_count @version.issues_count -json.open_issues_count @version.issues_count - @version.closed_issues_count -json.close_issues_count @version.closed_issues_count +json.issues_count @version_issues_size +json.open_issues_count @version_issues_size - @version_close_issues_size +json.close_issues_count @version_close_issues_size json.limit @limit json.user_name @version.version_user.try(:show_real_name) json.user_login @version.version_user.try(:login) diff --git a/config/configuration.yml.example b/config/configuration.yml.example index e7f40f00..9b012277 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -1,6 +1,7 @@ default: &default # 用户登入的时候设置/登出的时候清空 autologin_cookie_name: 'autologin_trustie' + platform_url: 'http://localhost:3000' #附件上传路径 diff --git a/config/database.yml.example b/config/database.yml.example index dae8f881..b0f1f2be 100644 --- a/config/database.yml.example +++ b/config/database.yml.example @@ -17,6 +17,13 @@ default: &default username: root password: 123456 # socket: /var/run/mysqld/mysqld.sock + gitea_server: + aadapter: mysql2 + database: gitea_development + host: 127.0.0.1 + username: root + password: "123456" + encoding: utf8 development: <<: *default diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index def30285..12faf10f 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -4,5 +4,5 @@ # Rails.application.config.session_store :active_record_store # Be sure to restart your server when you modify this file. -Rails.application.config.session_store :cache_store, :expire_after => 24.hours, :httponly => false, :secure => false, key: '_educoder_session', domain: :all +Rails.application.config.session_store :cache_store, :expire_after => 24.hours, :httponly => true, :secure => false, key: '_educoder_session', domain: :all diff --git a/config/routes.rb b/config/routes.rb index 17758613..a3cc196e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -71,6 +71,8 @@ Rails.application.routes.draw do # end end + resources :public_keys, only: [:index, :create, :destroy] + resources :statistic, only: [:index] do collection do get :platform_profile @@ -417,7 +419,6 @@ Rails.application.routes.draw do member do get :files get :detail - get :archive get :entries match :sub_entries, :via => [:get, :put] get :commits @@ -432,6 +433,7 @@ Rails.application.routes.draw do get 'commits/:sha', to: 'repositories#commit', as: 'commit' get 'readme' get 'languages' + get 'archive/:archive', to: 'repositories#archive', as: "archive", constraints: { archive: /.+/, format: /(zip|gzip)/ } end end @@ -570,6 +572,12 @@ Rails.application.routes.draw do post :cancel end end + resources :webhooks, except: [:show, :new] do + member do + get :tasks + post :test + end + end scope do get( '/blob/*id/diff', diff --git a/db/migrate/20210621090005_add_project_language_index_to_projects.rb b/db/migrate/20210621090005_add_project_language_index_to_projects.rb new file mode 100644 index 00000000..d0959168 --- /dev/null +++ b/db/migrate/20210621090005_add_project_language_index_to_projects.rb @@ -0,0 +1,7 @@ +class AddProjectLanguageIndexToProjects < ActiveRecord::Migration[5.2] + def change + add_index :projects, :project_category_id + add_index :projects, :project_language_id + add_index :projects, :license_id + end +end diff --git a/db/migrate/20210624101058_change_columns_name_from_pull_requests.rb b/db/migrate/20210624101058_change_columns_name_from_pull_requests.rb new file mode 100644 index 00000000..e24af231 --- /dev/null +++ b/db/migrate/20210624101058_change_columns_name_from_pull_requests.rb @@ -0,0 +1,22 @@ +class ChangeColumnsNameFromPullRequests < ActiveRecord::Migration[5.2] + def change + rename_column :pull_requests, :pull_request_id, :gitea_id + rename_column :pull_requests, :gpid, :gitea_number + + + PullRequest.find_each do |pr| + next if pr.gitea_number.blank? + + project = pr.project + next if project.blank? + + owner = project&.owner + gitea_pull = Gitea::PullRequest::GetService.call(owner.login, project.identifier, pr.gitea_number, owner&.gitea_token) + + next if gitea_pull.blank? + + pr.update_column(:gitea_id, gitea_pull["id"]) + end + + end +end diff --git a/lib/tasks/sync_projects_by_forked_project.rake b/lib/tasks/sync_projects_by_forked_project.rake new file mode 100644 index 00000000..d6cd1f21 --- /dev/null +++ b/lib/tasks/sync_projects_by_forked_project.rake @@ -0,0 +1,26 @@ +namespace :sync_projects_by_forked_project do + desc "sync projects is_public by forked project" + task is_public: :environment do + count = 0 + Project.where.not(forked_from_project_id: nil).group(:forked_from_project_id).count.each do |k, _| + project = Project.find_by_id(k) + need_update_forked_projects = Project.where(forked_from_project_id: k) + need_update_forked_projects.update_all(is_public: project&.is_public) + need_update_forked_repositories = Repository.where(project_id: need_update_forked_projects.ids) + need_update_forked_repositories.update_all(hidden: !project&.is_public) + count +=need_update_forked_projects.size + end + puts "共同步了#{count}个项目" + end + + task destroy: :environment do + count = 0 + Project.where.not(forked_from_project_id: nil).find_each do |project| + if project.forked_from_project.nil? + project.update(forked_from_project_id: nil) + count +=1 + end + end + puts "共同步了#{count}个项目" + end +end \ No newline at end of file diff --git a/public/docs/api.html b/public/docs/api.html index 5061a1ac..35099a4e 100644 --- a/public/docs/api.html +++ b/public/docs/api.html @@ -325,6 +325,20 @@ +获取public_keys列表,支持分页
+ +++示例:
+
curl -X GET \
+http://localhost:3000/api/public_keys.json
+
await octokit.request('GET /api/public_keys.json')
+
GET api/public_keys.json
参数 | +必选 | +默认 | +类型 | +字段说明 | +
---|---|---|---|---|
page | +否 | +1 | +int | +页码 | +
limit | +否 | +15 | +int | +每页数量 | +
参数 | +类型 | +字段说明 | +
---|---|---|
total_count | +int | +总数 | +
public_keys.id | +int | +ID | +
public_keys.name | +string | +密钥标题 | +
public_keys.content | +string | +密钥内容 | +
public_keys.fingerprint | +string | +密钥标识 | +
public_keys.created_time | +string | +密钥创建时间 | +
++返回的JSON示例:
+
{
+ "total_count": 1,
+ "public_keys": [
+ {
+ "id": 16,
+ "name": "xxx",
+ "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
+ "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
+ "created_unix": 1626246596,
+ "created_time": "2021/07/14 15:09"
+ }
+ ]
+}
+
创建public_key
+ +++示例:
+
curl -X POST \
+http://localhost:3000/api/public_keys.json
+
await octokit.request('POST /api/public_keys.json')
+
POST api/public_keys.json
参数 | +必选 | +默认 | +类型 | +字段说明 | +
---|---|---|---|---|
key | +是 | +否 | +string | +密钥 | +
title | +是 | +否 | +string | +密钥标题 | +
++请求的JSON示例: +
+json +{ + "public_key": { + "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com", + "title": "xxx" + } +} +
参数 | +类型 | +字段说明 | +
---|---|---|
total_count | +int | +总数 | +
id | +int | +ID | +
name | +string | +密钥标题 | +
content | +string | +密钥内容 | +
fingerprint | +string | +密钥标识 | +
created_time | +string | +密钥创建时间 | +
++返回的JSON示例:
+
{
+ "id": 17,
+ "name": "xxx",
+ "content": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDe5ETOTB5PcmcYJkIhfF7+mxmJQDCLg7/LnMoKHpKoo/jYUnFU9OjfsxVo3FTNUvh2475WXMAur5KsFoNKjK9+JHxvoXyJKmyVPWgXU/NRxQyaWPnPLPK8qPRF5ksJE6feBOqtsdxsvBiHs2r1NX/U26Ecnpr6avudD0cmyrEfbYMWbupLrhsd39dswPT73f3W5jc7B9Y47Ioiv8UOju3ABt1+kpuAjaaVC6VtUQoEFiZb1y33yBnyePya7dvFyApyD4ILyyIG2rtZWK7l53YFnwZDuFsTWjEEEQD0U4FBSFdH5wtwx0WQLMSNyTtaFBSG0kJ+uiQQIrxlvikcm63df7zbC3/rWLPsKgW122Zt966dcpFqiCiJNDKZPPw3qpg8TBL6X+qIZ+FxVEk/16/zScpyEfoxQp0GvgxI7hPLErmfkC5tMsib8MAXYBNyvJXna0vg/wOaNNIaI4SAH9Ksh3f/TtalYVjp6WxIwVBfnbq51WnmlnEXePtX6XjAGL+GbF2VQ1nv/IzrY09tNbTV6wQsrSIP3VDzYQxdJ1rdsVNMoJB0H2Pu0NdcSz53Wx45N+myD0QnE05ss+zDp5StY90OYsx2aCo6qAA8Qn2jUjdta7MQWwkPfKrta4tTQ0XbWMjx4/E1+l3J5liwZkl2XOGOwhfXdRsBjaEziZ18kQ== yystopf@163.com",
+ "fingerprint": "SHA256:cU8AK/+roqUUyiaYXIdS2Nj4+Rb2p6rqWSeRDc+aqKM",
+ "created_time": "2021/07/14 15:26"
+}
+
删除public_key
+ +++示例:
+
curl -X DELETE \
+http://localhost:3000/api/public_keys/:id.json
+
await octokit.request('DELETE /api/public_keys/:id.json')
+
DELETE api/public_keys/:id.json
参数 | +必选 | +默认 | +类型 | +字段说明 | +
---|---|---|---|---|
id | +是 | +否 | +int | +密钥ID | +
++返回的JSON示例:
+
{
+ "status": 0,
+ "message": "success"
+}
+