1# frozen_string_literal: true
2
3module Snippets
4  class BaseService < ::BaseProjectService
5    UPDATE_COMMIT_MSG = 'Update snippet'
6    INITIAL_COMMIT_MSG = 'Initial commit'
7
8    CreateRepositoryError = Class.new(StandardError)
9
10    attr_reader :uploaded_assets, :snippet_actions
11
12    def initialize(project: nil, current_user: nil, params: {})
13      super
14
15      @uploaded_assets = Array(@params.delete(:files).presence)
16
17      input_actions = Array(@params.delete(:snippet_actions).presence)
18      @snippet_actions = SnippetInputActionCollection.new(input_actions, allowed_actions: restricted_files_actions)
19    end
20
21    private
22
23    def visibility_allowed?(visibility_level)
24      Gitlab::VisibilityLevel.allowed_for?(current_user, visibility_level)
25    end
26
27    def forbidden_visibility_error(snippet)
28      deny_visibility_level(snippet)
29
30      snippet_error_response(snippet, 403)
31    end
32
33    def valid_params?
34      return true if snippet_actions.empty?
35
36      (params.keys & [:content, :file_name]).none? && snippet_actions.valid?
37    end
38
39    def invalid_params_error(snippet)
40      if snippet_actions.valid?
41        [:content, :file_name].each do |key|
42          snippet.errors.add(key, 'and snippet files cannot be used together') if params.key?(key)
43        end
44      else
45        snippet.errors.add(:snippet_actions, 'have invalid data')
46      end
47
48      snippet_error_response(snippet, 422)
49    end
50
51    def snippet_error_response(snippet, http_status)
52      ServiceResponse.error(
53        message: snippet.errors.full_messages.to_sentence,
54        http_status: http_status,
55        payload: { snippet: snippet }
56      )
57    end
58
59    def add_snippet_repository_error(snippet:, error:)
60      message = repository_error_message(error)
61
62      snippet.errors.add(:repository, message)
63    end
64
65    def repository_error_message(error)
66      message = self.is_a?(Snippets::CreateService) ? _("Error creating the snippet") : _("Error updating the snippet")
67
68      # We only want to include additional error detail in the message
69      # if the error is not a CommitError because we cannot guarantee the message
70      # will be user-friendly
71      message += " - #{error.message}" unless error.instance_of?(SnippetRepository::CommitError)
72
73      message
74    end
75
76    def files_to_commit(snippet)
77      snippet_actions.to_commit_actions.presence || build_actions_from_params(snippet)
78    end
79
80    def build_actions_from_params(snippet)
81      raise NotImplementedError
82    end
83
84    def restricted_files_actions
85      nil
86    end
87
88    def commit_attrs(snippet, msg)
89      {
90        branch_name: snippet.default_branch,
91        message: msg
92      }
93    end
94
95    def delete_repository(snippet)
96      snippet.repository.remove
97      snippet.snippet_repository&.delete
98
99      # Purge any existing value for repository_exists?
100      snippet.repository.expire_exists_cache
101    end
102  end
103end
104