summaryrefslogtreecommitdiff
path: root/app/controllers/concerns/snippets_actions.rb
blob: 51fc12398d964b6755831646a9111f869888bcc4 (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
# frozen_string_literal: true

module SnippetsActions
  extend ActiveSupport::Concern
  include SendsBlob
  include RendersNotes
  include RendersBlob
  include PaginatedCollection
  include Gitlab::NoteableMetadata

  included do
    skip_before_action :verify_authenticity_token,
      if: -> { action_name == 'show' && js_request? }

    before_action :redirect_if_binary, only: [:edit, :update]

    respond_to :html
  end

  def edit
    # We need to load some info from the existing blob
    snippet.content = blob.data
    snippet.file_name = blob.path

    render 'edit'
  end

  def raw
    workhorse_set_content_type!

    # Until we don't migrate all snippets to version
    # snippets we need to support old `SnippetBlob`
    # blobs
    if defined?(blob.snippet)
      send_data(
        convert_line_endings(blob.data),
        type: 'text/plain; charset=utf-8',
        disposition: content_disposition,
        filename: Snippet.sanitized_file_name(blob.name)
      )
    else
      send_blob(
        snippet.repository,
        blob,
        inline: content_disposition == 'inline',
        allow_caching: snippet.public?
      )
    end
  end

  def js_request?
    request.format.js?
  end

  # rubocop:disable Gitlab/ModuleWithInstanceVariables
  def show
    conditionally_expand_blob(blob)

    respond_to do |format|
      format.html do
        @note = Note.new(noteable: @snippet, project: @snippet.project)
        @noteable = @snippet

        @discussions = @snippet.discussions
        @notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
        render 'show'
      end

      format.json do
        render_blob_json(blob)
      end

      format.js do
        if @snippet.embeddable?
          render 'shared/snippets/show'
        else
          head :not_found
        end
      end
    end
  end

  def update
    update_params = snippet_params.merge(spammable_params)

    service_response = Snippets::UpdateService.new(@snippet.project, current_user, update_params).execute(@snippet)
    @snippet = service_response.payload[:snippet]

    handle_repository_error(:edit)
  end

  def destroy
    service_response = Snippets::DestroyService.new(current_user, @snippet).execute

    if service_response.success?
      redirect_to gitlab_dashboard_snippets_path(@snippet), status: :found
    elsif service_response.http_status == 403
      access_denied!
    else
      redirect_to gitlab_snippet_path(@snippet),
                  status: :found,
                  alert: service_response.message
    end
  end
  # rubocop:enable Gitlab/ModuleWithInstanceVariables

  private

  def content_disposition
    @disposition ||= params[:inline] == 'false' ? 'attachment' : 'inline'
  end

  # rubocop:disable Gitlab/ModuleWithInstanceVariables
  def blob
    return unless snippet

    @blob ||= if snippet.empty_repo?
                snippet.blob
              else
                snippet.blobs.first
              end
  end
  # rubocop:enable Gitlab/ModuleWithInstanceVariables

  def convert_line_endings(content)
    params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n")
  end

  def handle_repository_error(action)
    errors = Array(snippet.errors.delete(:repository))

    flash.now[:alert] = errors.first if errors.present?

    recaptcha_check_with_fallback(errors.empty?) { render action }
  end

  def redirect_if_binary
    redirect_to gitlab_snippet_path(snippet) if blob&.binary?
  end
end