summaryrefslogtreecommitdiff
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb8
-rw-r--r--app/models/grafana_integration.rb8
-rw-r--r--app/models/hooks/web_hook_log.rb7
-rw-r--r--app/models/integrations/campfire.rb58
-rw-r--r--app/models/integrations/drone_ci.rb1
-rw-r--r--app/models/integrations/jira.rb8
-rw-r--r--app/models/integrations/packagist.rb53
-rw-r--r--app/models/integrations/zentao.rb71
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/repository.rb10
-rw-r--r--app/models/snippet.rb2
-rw-r--r--app/models/todo.rb1
-rw-r--r--app/models/user.rb14
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