summaryrefslogtreecommitdiff
path: root/lib/api/helpers/internal_helpers.rb
blob: c8e96c7c5db4867e03217349a3e63f9a82f93b22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# frozen_string_literal: true

module API
  module Helpers
    module InternalHelpers
      attr_reader :redirected_path

      delegate :wiki?, to: :repo_type

      def actor
        @actor ||= Support::GitAccessActor.from_params(params)
      end

      def repo_type
        set_project unless defined?(@repo_type) # rubocop:disable Gitlab/ModuleWithInstanceVariables
        @repo_type # rubocop:disable Gitlab/ModuleWithInstanceVariables
      end

      def project
        set_project unless defined?(@project) # rubocop:disable Gitlab/ModuleWithInstanceVariables
        @project # rubocop:disable Gitlab/ModuleWithInstanceVariables
      end

      def access_checker_for(actor, protocol)
        access_checker_klass.new(actor.key_or_user, project, protocol,
          authentication_abilities: ssh_authentication_abilities,
          namespace_path: namespace_path,
          project_path: project_path,
          redirected_path: redirected_path)
      end

      def access_checker_klass
        repo_type.access_checker_class
      end

      def ssh_authentication_abilities
        [
          :read_project,
          :download_code,
          :push_code
        ]
      end

      def parse_env
        return {} if params[:env].blank?

        JSON.parse(params[:env])
      rescue JSON::ParserError
        {}
      end

      def log_user_activity(actor)
        commands = Gitlab::GitAccess::DOWNLOAD_COMMANDS

        ::Users::ActivityService.new(actor).execute if commands.include?(params[:action])
      end

      def merge_request_urls
        ::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
      end

      def process_mr_push_options(push_options, project, user, changes)
        Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/61359')

        service = ::MergeRequests::PushOptionsHandlerService.new(
          project,
          user,
          changes,
          push_options
        ).execute

        if service.errors.present?
          push_options_warning(service.errors.join("\n\n"))
        end
      end

      def push_options_warning(warning)
        options = Array.wrap(params[:push_options]).map { |p| "'#{p}'" }.join(' ')
        "WARNINGS:\nError encountered with push options #{options}: #{warning}"
      end

      def redis_ping
        result = Gitlab::Redis::SharedState.with { |redis| redis.ping }

        result == 'PONG'
      rescue => e
        Rails.logger.warn("GitLab: An unexpected error occurred in pinging to Redis: #{e}") # rubocop:disable Gitlab/RailsLogger
        false
      end

      def project_path
        project&.path || project_path_match[:project_path]
      end

      def namespace_path
        project&.namespace&.full_path || project_path_match[:namespace_path]
      end

      private

      def project_path_match
        @project_path_match ||= params[:project].match(Gitlab::PathRegex.full_project_git_path_regex) || {}
      end

      # rubocop:disable Gitlab/ModuleWithInstanceVariables
      def set_project
        if params[:gl_repository]
          @project, @repo_type = Gitlab::GlRepository.parse(params[:gl_repository])
          @redirected_path = nil
        elsif params[:project]
          @project, @repo_type, @redirected_path = Gitlab::RepoPath.parse(params[:project])
        else
          @project, @repo_type, @redirected_path = nil, nil, nil
        end
      end
      # rubocop:enable Gitlab/ModuleWithInstanceVariables

      # Project id to pass between components that don't share/don't have
      # access to the same filesystem mounts
      def gl_repository
        repo_type.identifier_for_repositorable(project)
      end

      def gl_project_path
        repository.full_path
      end

      # Return the repository depending on whether we want the wiki or the
      # regular repository
      def repository
        @repository ||= repo_type.repository_for(project)
      end

      # Return the Gitaly Address if it is enabled
      def gitaly_payload(action)
        return unless %w[git-receive-pack git-upload-pack git-upload-archive].include?(action)

        {
          repository: repository.gitaly_repository,
          address: Gitlab::GitalyClient.address(project.repository_storage),
          token: Gitlab::GitalyClient.token(project.repository_storage),
          features: Feature::Gitaly.server_feature_flags
        }
      end
    end
  end
end