diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/error_tracking/project_error_tracking_setting.rb | 8 | ||||
-rw-r--r-- | app/models/grafana_integration.rb | 8 | ||||
-rw-r--r-- | app/models/hooks/web_hook_log.rb | 7 | ||||
-rw-r--r-- | app/models/integrations/campfire.rb | 58 | ||||
-rw-r--r-- | app/models/integrations/drone_ci.rb | 1 | ||||
-rw-r--r-- | app/models/integrations/jira.rb | 8 | ||||
-rw-r--r-- | app/models/integrations/packagist.rb | 53 | ||||
-rw-r--r-- | app/models/integrations/zentao.rb | 71 | ||||
-rw-r--r-- | app/models/project.rb | 1 | ||||
-rw-r--r-- | app/models/repository.rb | 10 | ||||
-rw-r--r-- | app/models/snippet.rb | 2 | ||||
-rw-r--r-- | app/models/todo.rb | 1 | ||||
-rw-r--r-- | app/models/user.rb | 14 |
13 files changed, 136 insertions, 106 deletions
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb index 30382a1c205..4953f24755c 100644 --- a/app/models/error_tracking/project_error_tracking_setting.rb +++ b/app/models/error_tracking/project_error_tracking_setting.rb @@ -44,6 +44,8 @@ module ErrorTracking key: Settings.attr_encrypted_db_key_base_32, algorithm: 'aes-256-gcm' + before_validation :reset_token + after_save :clear_reactive_cache! # When a user enables the integrated error tracking @@ -182,6 +184,12 @@ module ErrorTracking private + def reset_token + if api_url_changed? && !encrypted_token_changed? + self.token = nil + end + end + def ensure_issue_belongs_to_project!(project_id_from_api) raise 'The Sentry issue appers to be outside of the configured Sentry project' if Integer(project_id_from_api) != ensure_sentry_project_id! end diff --git a/app/models/grafana_integration.rb b/app/models/grafana_integration.rb index 00213732fee..0358e37c58b 100644 --- a/app/models/grafana_integration.rb +++ b/app/models/grafana_integration.rb @@ -18,6 +18,8 @@ class GrafanaIntegration < ApplicationRecord validates :enabled, inclusion: { in: [true, false] } + before_validation :reset_token + scope :enabled, -> { where(enabled: true) } def client @@ -36,6 +38,12 @@ class GrafanaIntegration < ApplicationRecord private + def reset_token + if grafana_url_changed? && !encrypted_token_changed? + self.token = nil + end + end + def token decrypt(:token, encrypted_token) end diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb index 8c0565e4a38..04d6d1ebd5c 100644 --- a/app/models/hooks/web_hook_log.rb +++ b/app/models/hooks/web_hook_log.rb @@ -20,6 +20,7 @@ class WebHookLog < ApplicationRecord validates :web_hook, presence: true before_save :obfuscate_basic_auth + before_save :redact_author_email def self.recent where('created_at >= ?', 2.days.ago.beginning_of_day) @@ -39,4 +40,10 @@ class WebHookLog < ApplicationRecord def obfuscate_basic_auth self.url = safe_url end + + def redact_author_email + return unless self.request_data.dig('commit', 'author', 'email').present? + + self.request_data['commit']['author']['email'] = _('[REDACTED]') + end end diff --git a/app/models/integrations/campfire.rb b/app/models/integrations/campfire.rb index 7889cd8f9a9..3e19ec5bc4b 100644 --- a/app/models/integrations/campfire.rb +++ b/app/models/integrations/campfire.rb @@ -2,8 +2,35 @@ module Integrations class Campfire < Integration - prop_accessor :token, :subdomain, :room + SUBDOMAIN_REGEXP = %r{\A[a-z](?:[a-z0-9-]*[a-z0-9])?\z}i.freeze + validates :token, presence: true, if: :activated? + validates :room, + allow_blank: true, + numericality: { only_integer: true, greater_than: 0 } + validates :subdomain, + allow_blank: true, + format: { with: SUBDOMAIN_REGEXP }, length: { in: 1..63 } + + field :token, + type: 'password', + title: -> { s_('Campfire token') }, + help: -> { s_('CampfireService|API authentication token from Campfire.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '', + required: true + + field :subdomain, + title: -> { s_('Campfire subdomain (optional)') }, + placeholder: '', + exposes_secrets: true, + help: -> { s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.') % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe } } + + field :room, + title: -> { s_('Campfire room ID (optional)') }, + placeholder: '123456', + help: -> { s_('CampfireService|From the end of the room URL.') } def title 'Campfire' @@ -22,35 +49,6 @@ module Integrations 'campfire' end - def fields - [ - { - type: 'password', - name: 'token', - title: _('Campfire token'), - help: s_('CampfireService|API authentication token from Campfire.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'subdomain', - title: _('Campfire subdomain (optional)'), - placeholder: '', - help: s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.') % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe } - }, - { - type: 'text', - name: 'room', - title: _('Campfire room ID (optional)'), - placeholder: '123456', - help: s_('CampfireService|From the end of the room URL.') - } - ] - end - def self.supported_events %w(push) end diff --git a/app/models/integrations/drone_ci.rb b/app/models/integrations/drone_ci.rb index 0c65ed8cd5f..cb81ab21ebe 100644 --- a/app/models/integrations/drone_ci.rb +++ b/app/models/integrations/drone_ci.rb @@ -13,6 +13,7 @@ module Integrations field :drone_url, title: s_('ProjectService|Drone server URL'), placeholder: 'http://drone.example.com', + exposes_secrets: true, required: true field :token, diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb index 992bd01bf5f..f91e8f904af 100644 --- a/app/models/integrations/jira.rb +++ b/app/models/integrations/jira.rb @@ -219,7 +219,9 @@ module Integrations # support any events. end - def find_issue(issue_key, rendered_fields: false, transitions: false) + def find_issue(issue_key, rendered_fields: false, transitions: false, restrict_project_key: false) + return if restrict_project_key && parse_project_from_issue_key(issue_key) != project_key + expands = [] expands << 'renderedFields' if rendered_fields expands << 'transitions' if transitions @@ -317,6 +319,10 @@ module Integrations private + def parse_project_from_issue_key(issue_key) + issue_key.gsub(Gitlab::Regex.jira_issue_key_project_key_extraction_regex, '') + end + def branch_name(commit) commit.first_ref_by_oid(project.repository) end diff --git a/app/models/integrations/packagist.rb b/app/models/integrations/packagist.rb index 758c9e4761b..502e509f7b9 100644 --- a/app/models/integrations/packagist.rb +++ b/app/models/integrations/packagist.rb @@ -5,7 +5,27 @@ module Integrations include HasWebHook extend Gitlab::Utils::Override - prop_accessor :username, :token, :server + field :username, + title: -> { s_('Username') }, + help: -> { s_('Enter your Packagist username.') }, + placeholder: '', + required: true + + field :token, + type: 'password', + title: -> { s_('Token') }, + help: -> { s_('Enter your Packagist token.') }, + non_empty_password_title: -> { s_('ProjectService|Enter new token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + placeholder: '', + required: true + + field :server, + title: -> { s_('Server (optional)') }, + help: -> { s_('Enter your Packagist server. Defaults to https://packagist.org.') }, + placeholder: 'https://packagist.org', + exposes_secrets: true, + required: false validates :username, presence: true, if: :activated? validates :token, presence: true, if: :activated? @@ -22,37 +42,6 @@ module Integrations 'packagist' end - def fields - [ - { - type: 'text', - name: 'username', - title: _('Username'), - help: s_('Enter your Packagist username.'), - placeholder: '', - required: true - }, - { - type: 'password', - name: 'token', - title: _('Token'), - help: s_('Enter your Packagist token.'), - non_empty_password_title: s_('ProjectService|Enter new token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - placeholder: '', - required: true - }, - { - type: 'text', - name: 'server', - title: _('Server (optional)'), - help: s_('Enter your Packagist server. Defaults to https://packagist.org.'), - placeholder: 'https://packagist.org', - required: false - } - ] - end - def self.supported_events %w(push merge_request tag_push) end diff --git a/app/models/integrations/zentao.rb b/app/models/integrations/zentao.rb index c33df465fde..53194089296 100644 --- a/app/models/integrations/zentao.rb +++ b/app/models/integrations/zentao.rb @@ -1,10 +1,33 @@ # frozen_string_literal: true module Integrations - class Zentao < Integration + class Zentao < BaseIssueTracker include Gitlab::Routing - data_field :url, :api_url, :api_token, :zentao_product_xid + self.field_storage = :data_fields + + field :url, + title: -> { s_('ZentaoIntegration|ZenTao Web URL') }, + placeholder: 'https://www.zentao.net', + help: -> { s_('ZentaoIntegration|Base URL of the ZenTao instance.') }, + exposes_secrets: true, + required: true + + field :api_url, + title: -> { s_('ZentaoIntegration|ZenTao API URL (optional)') }, + help: -> { s_('ZentaoIntegration|If different from Web URL.') }, + exposes_secrets: true + + field :api_token, + type: 'password', + title: -> { s_('ZentaoIntegration|ZenTao API token') }, + non_empty_password_title: -> { s_('ZentaoIntegration|Enter new ZenTao API token') }, + non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current token.') }, + required: true + + field :zentao_product_xid, + title: -> { s_('ZentaoIntegration|ZenTao Product ID') }, + required: true validates :url, public_url: true, presence: true, if: :activated? validates :api_url, public_url: true, allow_blank: true @@ -19,6 +42,17 @@ module Integrations zentao_tracker_data || self.build_zentao_tracker_data end + alias_method :project_url, :url + + def set_default_data + return unless issues_tracker.present? + + return if url + + data_fields.url ||= issues_tracker['url'] + data_fields.api_url ||= issues_tracker['api_url'] + end + def title 'ZenTao' end @@ -47,39 +81,6 @@ module Integrations %w() end - def fields - [ - { - type: 'text', - name: 'url', - title: s_('ZentaoIntegration|ZenTao Web URL'), - placeholder: 'https://www.zentao.net', - help: s_('ZentaoIntegration|Base URL of the ZenTao instance.'), - required: true - }, - { - type: 'text', - name: 'api_url', - title: s_('ZentaoIntegration|ZenTao API URL (optional)'), - help: s_('ZentaoIntegration|If different from Web URL.') - }, - { - type: 'password', - name: 'api_token', - title: s_('ZentaoIntegration|ZenTao API token'), - non_empty_password_title: s_('ZentaoIntegration|Enter new ZenTao API token'), - non_empty_password_help: s_('ProjectService|Leave blank to use your current token.'), - required: true - }, - { - type: 'text', - name: 'zentao_product_xid', - title: s_('ZentaoIntegration|ZenTao Product ID'), - required: true - } - ] - end - private def client diff --git a/app/models/project.rb b/app/models/project.rb index b66ec28b659..cf0dfc33490 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2018,6 +2018,7 @@ class Project < ApplicationRecord end def after_import + repository.remove_prohibited_branches repository.expire_content_cache wiki.repository.expire_content_cache diff --git a/app/models/repository.rb b/app/models/repository.rb index dc0b5b54fb0..d10f4089061 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1167,6 +1167,16 @@ class Repository @cache ||= Gitlab::RepositoryCache.new(self) end + def remove_prohibited_branches + return unless exists? + + prohibited_branches = raw_repository.branch_names.select { |name| name.match(/\A\h{40}\z/) } + + return if prohibited_branches.blank? + + prohibited_branches.each { |name| raw_repository.delete_branch(name) } + end + private # TODO Genericize finder, later split this on finders by Ref or Oid diff --git a/app/models/snippet.rb b/app/models/snippet.rb index cf4b83d44c2..2001577c88b 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -70,8 +70,6 @@ class Snippet < ApplicationRecord }, if: :content_changed? - validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values } - after_create :create_statistics # Scopes diff --git a/app/models/todo.rb b/app/models/todo.rb index 45ab770a0f6..3f589faa4d8 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -74,6 +74,7 @@ class Todo < ApplicationRecord scope :for_commit, -> (id) { where(commit_id: id) } scope :with_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: [:route, :owner] }]) } scope :joins_issue_and_assignees, -> { left_joins(issue: :assignees) } + scope :for_internal_notes, -> { joins(:note).where(note: { confidential: true }) } enum resolved_by_action: { system_done: 0, api_all_done: 1, api_done: 2, mark_all_done: 3, mark_done: 4 }, _prefix: :resolved_by diff --git a/app/models/user.rb b/app/models/user.rb index ce8ec7ff5ac..b59fc5069d6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -600,23 +600,24 @@ class User < ApplicationRecord end end - # Find a User by their primary email or any associated secondary email + # Find a User by their primary email or any associated confirmed secondary email def find_by_any_email(email, confirmed: false) return unless email by_any_email(email, confirmed: confirmed).take end - # Returns a relation containing all the users for the given email addresses + # Returns a relation containing all found users by their primary email + # or any associated confirmed secondary email # # @param emails [String, Array<String>] email addresses to check - # @param confirmed [Boolean] Only return users where the email is confirmed + # @param confirmed [Boolean] Only return users where the primary email is confirmed def by_any_email(emails, confirmed: false) from_users = by_user_email(emails) from_users = from_users.confirmed if confirmed - from_emails = by_emails(emails) - from_emails = from_emails.confirmed.merge(Email.confirmed) if confirmed + from_emails = by_emails(emails).merge(Email.confirmed) + from_emails = from_emails.confirmed if confirmed items = [from_users, from_emails] @@ -721,6 +722,7 @@ class User < ApplicationRecord matched_by_email_user_id = email_table .project(email_table[:user_id]) .where(email_table[:email].eq(email_address)) + .where(email_table[:confirmed_at].not_eq(nil)) .take(1) # at most 1 record as there is a unique constraint where( @@ -1433,7 +1435,7 @@ class User < ApplicationRecord all_emails = [] all_emails << email unless temp_oauth_email? all_emails << private_commit_email if include_private_email - all_emails.concat(emails.map(&:email)) + all_emails.concat(emails.filter_map { |email| email.email if email.confirmed? }) all_emails.uniq end |