| @@ -135,4 +135,4 @@ gem 'doorkeeper' | |||||
| gem 'doorkeeper-jwt' | gem 'doorkeeper-jwt' | ||||
| gem 'gitea-client', '~> 0.10.4' | |||||
| gem 'gitea-client', '~> 0.10.5' | |||||
| @@ -2,6 +2,7 @@ class Api::V1::BaseController < ApplicationController | |||||
| include Api::ProjectHelper | include Api::ProjectHelper | ||||
| include Api::UserHelper | include Api::UserHelper | ||||
| include Api::PullHelper | |||||
| # before_action :doorkeeper_authorize! | # before_action :doorkeeper_authorize! | ||||
| # skip_before_action :user_setup | # skip_before_action :user_setup | ||||
| @@ -30,18 +31,18 @@ class Api::V1::BaseController < ApplicationController | |||||
| # 具有对仓库的管理权限 | # 具有对仓库的管理权限 | ||||
| def require_manager_above | def require_manager_above | ||||
| @project = load_project | @project = load_project | ||||
| return render_forbidden unless current_user.admin? && @project.manager?(current_user) | |||||
| return render_forbidden if !current_user.admin? && !@project.manager?(current_user) | |||||
| end | end | ||||
| # 具有对仓库的操作权限 | # 具有对仓库的操作权限 | ||||
| def require_operate_above | def require_operate_above | ||||
| @project = load_project | @project = load_project | ||||
| return render_forbidden unless current_user.admin? && @project.operator?(current_user) | |||||
| return render_forbidden if !current_user.admin? && !@project.operator?(current_user) | |||||
| end | end | ||||
| # 具有对仓库的访问权限 | # 具有对仓库的访问权限 | ||||
| def require_public_and_member_above | def require_public_and_member_above | ||||
| @project = load_project | @project = load_project | ||||
| return render_forbidden unless @project.is_public || (current_user.admin? && @project.member?(current_user)) | |||||
| return render_forbidden if !@project.is_public && !current_user.admin? && !@project.member?(current_user) | |||||
| end | end | ||||
| end | end | ||||
| @@ -2,19 +2,4 @@ class Api::V1::Projects::Pulls::BaseController < Api::V1::BaseController | |||||
| before_action :require_public_and_member_above | before_action :require_public_and_member_above | ||||
| before_action :load_pull_request | before_action :load_pull_request | ||||
| def load_pull_request | |||||
| pull_request_id = params[:pull_id] || params[:id] | |||||
| @pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id) | |||||
| @issue = @pull_request&.issue | |||||
| if @pull_request | |||||
| logger.info "###########pull_request founded" | |||||
| @pull_request | |||||
| else | |||||
| logger.info "###########pull_request not found" | |||||
| @pull_request = nil | |||||
| render_not_found and return | |||||
| end | |||||
| @pull_request | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,2 @@ | |||||
| class Api::V1::Projects::Pulls::CommentsController < Api::V1::Projects::Pulls::BaseController | |||||
| end | |||||
| @@ -0,0 +1,22 @@ | |||||
| class Api::V1::Projects::Pulls::ReviewsController < Api::V1::Projects::Pulls::BaseController | |||||
| def index | |||||
| @reviews = @pull_request.reviews | |||||
| @reviews = kaminari_paginate(@reviews) | |||||
| end | |||||
| before_action :require_reviewer, only: [:create] | |||||
| def create | |||||
| @journal, @review = Api::V1::Projects::Pulls::Reviews::CreateService.call(@project, @pull_request, review_params, current_user) | |||||
| end | |||||
| private | |||||
| def require_reviewer | |||||
| return render_forbidden('您没有审查权限,请联系项目管理员') if !current_user.admin? && !@pull_request.reviewers.exists?(current_user.id) | |||||
| end | |||||
| def review_params | |||||
| params.require(:review).permit(:content, :commit_id, :status) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,20 @@ | |||||
| class Api::V1::Projects::PullsController < Api::V1::BaseController | |||||
| before_action :require_public_and_member_above | |||||
| def index | |||||
| @pulls = Api::V1::Projects::Pulls::ListService.call(@project, query_params) | |||||
| @pulls = kaminari_paginate(@pulls) | |||||
| end | |||||
| before_action :load_pull_request, only: [:show] | |||||
| def show | |||||
| @result_object = Api::V1::Projects::Pulls::GetService.call(@project, @pull_request, current_user&.gitea_token) | |||||
| @last_review = @pull_request.reviews.take | |||||
| end | |||||
| private | |||||
| def query_params | |||||
| params.permit(:status, :keyword, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,19 @@ | |||||
| module Api::PullHelper | |||||
| extend ActiveSupport::Concern | |||||
| def load_pull_request | |||||
| pull_request_id = params[:pull_id] || params[:id] | |||||
| @pull_request = @project.pull_requests.where(gitea_number: pull_request_id).where.not(id: pull_request_id).take || PullRequest.find_by_id(pull_request_id) | |||||
| @issue = @pull_request&.issue | |||||
| if @pull_request | |||||
| logger.info "###########pull_request founded" | |||||
| @pull_request | |||||
| else | |||||
| logger.info "###########pull_request not found" | |||||
| @pull_request = nil | |||||
| render_not_found and return | |||||
| end | |||||
| @pull_request | |||||
| end | |||||
| end | |||||
| @@ -176,7 +176,7 @@ class PullRequestsController < ApplicationController | |||||
| @issue_assign_to = @issue.get_assign_user | @issue_assign_to = @issue.get_assign_user | ||||
| @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, | @gitea_pull = Gitea::PullRequest::GetService.call(@owner.login, | ||||
| @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) | @repository.identifier, @pull_request.gitea_number, current_user&.gitea_token) | ||||
| @last_review = @pull_request.issue.reviews.take | |||||
| @last_review = @pull_request.reviews.take | |||||
| end | end | ||||
| def pr_merge | def pr_merge | ||||
| @@ -68,7 +68,6 @@ class Issue < ApplicationRecord | |||||
| has_many :issue_tags, through: :issue_tags_relates | has_many :issue_tags, through: :issue_tags_relates | ||||
| has_many :issue_times, dependent: :destroy | has_many :issue_times, dependent: :destroy | ||||
| has_many :issue_depends, dependent: :destroy | has_many :issue_depends, dependent: :destroy | ||||
| has_many :reviews, dependent: :destroy | |||||
| scope :issue_includes, ->{includes(:user)} | scope :issue_includes, ->{includes(:user)} | ||||
| scope :issue_many_includes, ->{includes(journals: :user)} | scope :issue_many_includes, ->{includes(journals: :user)} | ||||
| scope :issue_issue, ->{where(issue_classify: [nil,"issue"])} | scope :issue_issue, ->{where(issue_classify: [nil,"issue"])} | ||||
| @@ -25,7 +25,8 @@ | |||||
| class Journal < ApplicationRecord | class Journal < ApplicationRecord | ||||
| belongs_to :user | belongs_to :user | ||||
| belongs_to :issue, foreign_key: :journalized_id, :touch => true | |||||
| belongs_to :issue, foreign_key: :journalized_id, :touch => true, optional: true | |||||
| belongs_to :journalized, polymorphic: true | |||||
| has_many :journal_details, :dependent => :delete_all | has_many :journal_details, :dependent => :delete_all | ||||
| has_many :attachments, as: :container, dependent: :destroy | has_many :attachments, as: :container, dependent: :destroy | ||||
| @@ -32,12 +32,17 @@ class PullRequest < ApplicationRecord | |||||
| belongs_to :issue | belongs_to :issue | ||||
| belongs_to :user | belongs_to :user | ||||
| belongs_to :project, counter_cache: true, touch: true | belongs_to :project, counter_cache: true, touch: true | ||||
| # belongs_to :fork_project, foreign_key: :fork_project_id | |||||
| belongs_to :fork_project, class_name: 'Project', foreign_key: :fork_project_id, optional: true | |||||
| has_many :pull_request_assigns, foreign_key: :pull_request_id | has_many :pull_request_assigns, foreign_key: :pull_request_id | ||||
| has_many :pull_request_tags, foreign_key: :pull_request_id | has_many :pull_request_tags, foreign_key: :pull_request_id | ||||
| has_many :project_trends, as: :trend, dependent: :destroy | has_many :project_trends, as: :trend, dependent: :destroy | ||||
| has_many :attachments, as: :container, dependent: :destroy | has_many :attachments, as: :container, dependent: :destroy | ||||
| has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_number, class_name: 'Gitea::Pull' | has_one :gitea_pull, foreign_key: :id, primary_key: :gitea_number, class_name: 'Gitea::Pull' | ||||
| has_many :journals, :as => :journalized, :dependent => :destroy | |||||
| has_many :journal_details, through: :journals | |||||
| has_many :reviews, dependent: :destroy | |||||
| has_many :pull_requests_reviewers, dependent: :destroy | |||||
| has_many :reviewers, through: :pull_requests_reviewers | |||||
| scope :merged_and_closed, ->{where.not(status: 0)} | scope :merged_and_closed, ->{where.not(status: 0)} | ||||
| scope :opening, -> {where(status: 0)} | scope :opening, -> {where(status: 0)} | ||||
| @@ -0,0 +1,21 @@ | |||||
| # == Schema Information | |||||
| # | |||||
| # Table name: pull_requests_reviewers | |||||
| # | |||||
| # id :integer not null, primary key | |||||
| # pull_request_id :integer | |||||
| # reviewer_id :integer | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # | |||||
| # Indexes | |||||
| # | |||||
| # index_pull_requests_reviewers_on_pull_request_id (pull_request_id) | |||||
| # index_pull_requests_reviewers_on_reviewer_id (reviewer_id) | |||||
| # | |||||
| class PullRequestsReviewer < ApplicationRecord | |||||
| belongs_to :pull_request | |||||
| belongs_to :reviewers, class_name: 'User', foreign_key: :reviewer_id | |||||
| end | |||||
| @@ -2,24 +2,24 @@ | |||||
| # | # | ||||
| # Table name: reviews | # Table name: reviews | ||||
| # | # | ||||
| # id :integer not null, primary key | |||||
| # issue_id :integer | |||||
| # reviewer_id :integer | |||||
| # content :text(65535) | |||||
| # commit_id :string(255) | |||||
| # status :integer default("0") | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # id :integer not null, primary key | |||||
| # reviewer_id :integer | |||||
| # content :text(65535) | |||||
| # commit_id :string(255) | |||||
| # status :integer default("0") | |||||
| # created_at :datetime not null | |||||
| # updated_at :datetime not null | |||||
| # pull_request_id :integer | |||||
| # | # | ||||
| # Indexes | # Indexes | ||||
| # | # | ||||
| # index_reviews_on_issue_id (issue_id) | |||||
| # index_reviews_on_reviewer_id (reviewer_id) | |||||
| # index_reviews_on_pull_request_id (pull_request_id) | |||||
| # index_reviews_on_reviewer_id (reviewer_id) | |||||
| # | # | ||||
| class Review < ApplicationRecord | class Review < ApplicationRecord | ||||
| belongs_to :issue | |||||
| belongs_to :pull_request | |||||
| belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id | belongs_to :reviewer, class_name: 'User', foreign_key: :reviewer_id | ||||
| has_one :journal, dependent: :destroy | has_one :journal, dependent: :destroy | ||||
| @@ -0,0 +1,32 @@ | |||||
| class Api::V1::Projects::Pulls::GetService < ApplicationService | |||||
| attr_reader :project, :pull_request, :owner, :repo, :index, :token | |||||
| attr_accessor :gitea_data | |||||
| def initialize(project, pull_request, token = nil) | |||||
| @project = project | |||||
| @pull_request = pull_request | |||||
| @owner = project&.owner.login | |||||
| @repo = project&.identifier | |||||
| @index = pull_request.gitea_number | |||||
| @token = token | |||||
| end | |||||
| def call | |||||
| load_gitea_data | |||||
| gitea_data | |||||
| end | |||||
| private | |||||
| def request_params | |||||
| { | |||||
| access_token: token | |||||
| } | |||||
| end | |||||
| def load_gitea_data | |||||
| @gitea_data = $gitea_client.get_repos_pulls_by_owner_repo_index(owner, repo, index, {query: request_params}) | |||||
| # raise Error, '获取合并请求失败!' unless @gitea_data.is_a?(Hash) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,46 @@ | |||||
| class Api::V1::Projects::Pulls::ListService < ApplicationService | |||||
| include ActiveModel::Model | |||||
| attr_reader :project, :keyword, :status, :priority_id, :issue_tag_id, :version_id, :reviewer_id, :sort_by, :sort_direction | |||||
| attr_accessor :queried_pull_requests | |||||
| validates :status, inclusion: {in: [0, 1, 2], message: "请输入正确的Status"}, allow_nil: true | |||||
| validates :sort_by, inclusion: {in: PullRequest.column_names, message: '请输入正确的SortBy'} | |||||
| validates :sort_direction, inclusion: {in: %w(asc desc), message: '请输入正确的SortDirection'} | |||||
| def initialize(project, params={}) | |||||
| @project = project | |||||
| @keyword = params[:keyword] | |||||
| @status = params[:status].to_i | |||||
| @priority_id = params[:priority_id] | |||||
| @issue_tag_id = params[:issue_tag_id] | |||||
| @version_id = params[:version_id] | |||||
| @reviewer_id = params[:reviewer_id] | |||||
| @sort_by = params[:sort_by] || 'created_at' | |||||
| @sort_direction = params[:sort_direction] || 'desc' | |||||
| end | |||||
| def call | |||||
| raise Error, errors.full_messages.join(",") unless valid? | |||||
| pull_request_query_data | |||||
| queried_pull_requests | |||||
| end | |||||
| private | |||||
| def pull_request_query_data | |||||
| pull_requests = @project.pull_requests | |||||
| pull_requests = pull_requests.where(status: status) if status.present? | |||||
| pull_requests = pull_requests.where(issues: {priority_id: priority_id}) if priority_id.present? | |||||
| pull_requests = pull_requests.where(issue_tags: {id: issue_tag_id}) if issue_tag_id.present? | |||||
| pull_requests = pull_requests.where(issues: {fixed_version_id: version_id}) if version_id.present? | |||||
| pull_requests = pull_requests.where(users: {id: reviewer_id}) if reviewer_id.present? | |||||
| q = pull_requests.ransack(title_or_body_cont: keyword) | |||||
| scope = q.result.includes(:fork_project, :journals, :reviews, :reviewers, issue: [:journals, :priority, :version, :issue_tags]) | |||||
| scope = scope.order("pull_requests.#{sort_by} #{sort_direction}") | |||||
| @queried_pull_requests = scope | |||||
| end | |||||
| end | |||||
| @@ -24,17 +24,17 @@ class Api::V1::Projects::Pulls::Reviews::CreateService < ApplicationService | |||||
| end | end | ||||
| return @journal, @review | return @journal, @review | ||||
| rescue | |||||
| raise Error, '服务器错误,请联系系统管理员!' | |||||
| # rescue | |||||
| # raise Error, '服务器错误,请联系系统管理员!' | |||||
| end | end | ||||
| private | private | ||||
| def create_review | def create_review | ||||
| @review = issue.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id) | |||||
| @review = pull_request.reviews.create!(status: status, content: content, commit_id: commit_id, reviewer_id: @current_user.id) | |||||
| end | end | ||||
| def create_journal | def create_journal | ||||
| @journal = issue.journals.create!(notes: content, user_id: @current_user.id, review_id: @review.id) | |||||
| @journal = pull_request.journals.create!(notes: content, user_id: @current_user.id, review_id: @review.id) | |||||
| end | end | ||||
| end | end | ||||
| @@ -0,0 +1,25 @@ | |||||
| json.(pull, :id, :head, :base, :is_original) | |||||
| json.index pull.gitea_number | |||||
| json.status pull.status == 1 ? "merged" : (pull.status == 2 ? "closed" : "open") | |||||
| fork_project = pull&.fork_project | |||||
| if fork_project.present? | |||||
| json.fork_project do | |||||
| json.(fork_project, :id, :identifier) | |||||
| json.login fork_project&.owner&.login | |||||
| end | |||||
| end | |||||
| issue = pull&.issue | |||||
| json.issue do | |||||
| json.id issue&.id | |||||
| json.author do | |||||
| json.partial! '/api/v1/users/simple_user', user: issue&.user | |||||
| end | |||||
| json.priority issue&.priority.try(:name) | |||||
| json.version issue&.version.try(:name) | |||||
| json.comments_count issue.journals.count | |||||
| json.issue_tags issue.get_issue_tags | |||||
| end | |||||
| json.comments_count pull.journals.count | |||||
| @@ -0,0 +1,4 @@ | |||||
| json.total_count @pulls.total_count | |||||
| json.pulls @pulls.each do |pull| | |||||
| json.partial! 'api/v1/projects/pulls/simple_detail', pull: pull | |||||
| end | |||||
| @@ -0,0 +1,8 @@ | |||||
| json.reviewer do | |||||
| json.partial! "api/v1/users/simple_user", user: @review.reviewer | |||||
| end | |||||
| json.pull_request do | |||||
| json.partial! "api/v1/projects/pulls/simple_detail", pull: @review.pull_request | |||||
| end | |||||
| json.(@review, :id, :commit_id, :content, :status) | |||||
| json.created_at format_time(@review.created_at) | |||||
| @@ -0,0 +1,29 @@ | |||||
| json.partial! "api/v1/projects/pulls/simple_detail", pull: @pull_request | |||||
| json.merge_base @result_object['merge_base'] | |||||
| json.base_commit_sha @result_object['base']['sha'] | |||||
| json.head_commit_sha @result_object['head']['sha'] | |||||
| json.commit_num @result_object['commit_num'] | |||||
| json.changed_files @result_object['changed_files'] | |||||
| json.is_locked @result_object['is_locked'] | |||||
| json.mergeable @result_object['mergeable'] # 是否能合并 | |||||
| json.merged @result_object['merged'] | |||||
| json.merged_at @result_object['merged_at'].nil? ? '' : render_unix_time( @result_object['merged_at']) | |||||
| json.merge_commit_sha @result_object['merge_commit_sha'] | |||||
| json.merge_by do | |||||
| if @result_object['merged_by'] | |||||
| json.partial! 'api/v1/users/commit_user', locals: { user: render_cache_commit_author(@result_object['merged_by']), name: @result_object['merged_by']['login'] } | |||||
| else | |||||
| json.nil! | |||||
| end | |||||
| end | |||||
| json.last_review do | |||||
| if @last_review.present? | |||||
| json.(@last_review, :id, :commit_id, :content, :status) | |||||
| json.created_at format_time(@last_review.created_at) | |||||
| json.reviewer do | |||||
| json.partial! "api/v1/users/simple_user", user: @last_review.reviewer | |||||
| end | |||||
| else | |||||
| json.nil! | |||||
| end | |||||
| end | |||||
| @@ -25,6 +25,7 @@ defaults format: :json do | |||||
| get :diff | get :diff | ||||
| end | end | ||||
| end | end | ||||
| resources :reviews, only: [:index, :create] | |||||
| end | end | ||||
| resources :versions | resources :versions | ||||
| @@ -0,0 +1,9 @@ | |||||
| class CreatePullRequestsReviewers < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| create_table :pull_requests_reviewers do |t| | |||||
| t.belongs_to :pull_request, index: true | |||||
| t.belongs_to :reviewer, class_name: User, index:true | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,6 @@ | |||||
| class ChangeReviewsReferenceToPullRequests < ActiveRecord::Migration[5.2] | |||||
| def change | |||||
| remove_reference :reviews, :issue | |||||
| add_reference :reviews, :pull_request | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| require 'rails_helper' | |||||
| RSpec.describe PullRequestsReviewer, type: :model do | |||||
| pending "add some examples to (or delete) #{__FILE__}" | |||||
| end | |||||