Skip to content
GitLab
Next
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
GitLab.org
GitLab FOSS
Commits
477c2c26
Commit
477c2c26
authored
Sep 04, 2020
by
🤖 GitLab Bot 🤖
Browse files
Add latest changes from gitlab-org/gitlab@master
parent
4be2167e
Changes
73
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
73 changed files
with
1636 additions
and
309 deletions
+1636
-309
CHANGELOG.md
CHANGELOG.md
+0
-20
app/assets/javascripts/clusters/clusters_bundle.js
app/assets/javascripts/clusters/clusters_bundle.js
+1
-1
app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js
...d/components/filtered_search_bar/filtered_search_utils.js
+133
-0
app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js
...ontent_editor/services/build_html_to_markdown_renderer.js
+8
-0
app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph.js
..._editor/services/renderers/render_identifier_paragraph.js
+29
-2
app/controllers/admin/users_controller.rb
app/controllers/admin/users_controller.rb
+4
-3
app/controllers/profiles/notifications_controller.rb
app/controllers/profiles/notifications_controller.rb
+2
-4
app/finders/user_group_notification_settings_finder.rb
app/finders/user_group_notification_settings_finder.rb
+44
-0
app/graphql/resolvers/concerns/looks_ahead.rb
app/graphql/resolvers/concerns/looks_ahead.rb
+1
-1
app/graphql/resolvers/issues_resolver.rb
app/graphql/resolvers/issues_resolver.rb
+2
-1
app/graphql/types/issue_type.rb
app/graphql/types/issue_type.rb
+1
-2
app/helpers/emails_helper.rb
app/helpers/emails_helper.rb
+25
-1
app/mailers/devise_mailer.rb
app/mailers/devise_mailer.rb
+4
-0
app/models/concerns/admin_changed_password_notifier.rb
app/models/concerns/admin_changed_password_notifier.rb
+60
-0
app/models/issue.rb
app/models/issue.rb
+2
-1
app/models/user.rb
app/models/user.rb
+7
-0
app/services/auto_merge/base_service.rb
app/services/auto_merge/base_service.rb
+15
-0
app/services/merge_requests/create_pipeline_service.rb
app/services/merge_requests/create_pipeline_service.rb
+9
-3
app/views/clusters/clusters/_banner.html.haml
app/views/clusters/clusters/_banner.html.haml
+2
-2
app/views/devise/mailer/password_change_by_admin.html.haml
app/views/devise/mailer/password_change_by_admin.html.haml
+6
-0
app/views/devise/mailer/password_change_by_admin.text.erb
app/views/devise/mailer/password_change_by_admin.text.erb
+5
-0
changelogs/unreleased/229266-mlunoe-analytics-filter-module-list-values-follow-up.yml
...-mlunoe-analytics-filter-module-list-values-follow-up.yml
+6
-0
changelogs/unreleased/235889-jira-importer-user-mapping-shows-50-users-max.yml
.../235889-jira-importer-user-mapping-shows-50-users-max.yml
+5
-0
changelogs/unreleased/243760-fix-link-reference-definitions.yml
...logs/unreleased/243760-fix-link-reference-definitions.yml
+5
-0
changelogs/unreleased/27284-indicate-that-password-reset-was-initiated-by-an-admin-when-an-admi.yml
...password-reset-was-initiated-by-an-admin-when-an-admi.yml
+5
-0
changelogs/unreleased/bump-ado-image-to-v1-0-2.yml
changelogs/unreleased/bump-ado-image-to-v1-0-2.yml
+5
-0
changelogs/unreleased/cat-time-precision-2fa-ldap.yml
changelogs/unreleased/cat-time-precision-2fa-ldap.yml
+5
-0
changelogs/unreleased/fix-run-pipeline-in-target-project.yml
changelogs/unreleased/fix-run-pipeline-in-target-project.yml
+6
-0
changelogs/unreleased/fix_concurrent_backup.yml
changelogs/unreleased/fix_concurrent_backup.yml
+5
-0
changelogs/unreleased/id-remove-memoize-on-processing-ref-changes.yml
...nreleased/id-remove-memoize-on-processing-ref-changes.yml
+5
-0
changelogs/unreleased/sh-fix-backup-restore-race.yml
changelogs/unreleased/sh-fix-backup-restore-race.yml
+5
-0
config/feature_flags/development/ci_disallow_to_create_merge_request_pipelines_in_target_project.yml
...w_to_create_merge_request_pipelines_in_target_project.yml
+7
-0
config/locales/devise.en.yml
config/locales/devise.en.yml
+2
-0
doc/administration/index.md
doc/administration/index.md
+1
-1
doc/administration/operations/puma.md
doc/administration/operations/puma.md
+1
-1
doc/administration/raketasks/uploads/migrate.md
doc/administration/raketasks/uploads/migrate.md
+18
-1
doc/administration/uploads.md
doc/administration/uploads.md
+5
-5
doc/api/graphql/reference/gitlab_schema.graphql
doc/api/graphql/reference/gitlab_schema.graphql
+41
-0
doc/api/graphql/reference/gitlab_schema.json
doc/api/graphql/reference/gitlab_schema.json
+135
-0
doc/api/graphql/reference/index.md
doc/api/graphql/reference/index.md
+9
-0
doc/api/issues.md
doc/api/issues.md
+4
-4
doc/api/repository_submodules.md
doc/api/repository_submodules.md
+2
-2
doc/ci/quick_start/README.md
doc/ci/quick_start/README.md
+9
-8
doc/integration/elasticsearch.md
doc/integration/elasticsearch.md
+163
-159
doc/raketasks/backup_restore.md
doc/raketasks/backup_restore.md
+1
-1
doc/security/README.md
doc/security/README.md
+1
-1
doc/security/reset_user_password.md
doc/security/reset_user_password.md
+30
-5
doc/user/profile/notifications.md
doc/user/profile/notifications.md
+2
-1
doc/user/search/index.md
doc/user/search/index.md
+9
-0
lib/api/users.rb
lib/api/users.rb
+8
-2
lib/backup/repository.rb
lib/backup/repository.rb
+24
-4
lib/gitlab/ci/features.rb
lib/gitlab/ci/features.rb
+5
-2
locale/gitlab.pot
locale/gitlab.pot
+12
-0
spec/controllers/admin/users_controller_spec.rb
spec/controllers/admin/users_controller_spec.rb
+57
-28
spec/controllers/profiles/notifications_controller_spec.rb
spec/controllers/profiles/notifications_controller_spec.rb
+3
-4
spec/factories/issues.rb
spec/factories/issues.rb
+4
-0
spec/features/issues/incident_issue_spec.rb
spec/features/issues/incident_issue_spec.rb
+4
-7
spec/features/merge_request/user_sees_pipelines_spec.rb
spec/features/merge_request/user_sees_pipelines_spec.rb
+4
-0
spec/finders/user_group_notification_settings_finder_spec.rb
spec/finders/user_group_notification_settings_finder_spec.rb
+95
-0
spec/frontend/vue_shared/components/filtered_search_bar/filtered_search_utils_spec.js
...ponents/filtered_search_bar/filtered_search_utils_spec.js
+175
-9
spec/frontend/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer_spec.js
...t_editor/services/build_html_to_markdown_renderer_spec.js
+30
-0
spec/frontend/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph_spec.js
...or/services/renderers/render_identifier_paragraph_spec.js
+44
-4
spec/helpers/emails_helper_spec.rb
spec/helpers/emails_helper_spec.rb
+35
-0
spec/lib/backup/repository_spec.rb
spec/lib/backup/repository_spec.rb
+27
-3
spec/mailers/devise_mailer_spec.rb
spec/mailers/devise_mailer_spec.rb
+29
-0
spec/models/issue_spec.rb
spec/models/issue_spec.rb
+3
-2
spec/models/user_spec.rb
spec/models/user_spec.rb
+90
-0
spec/requests/api/graphql/project/issues_spec.rb
spec/requests/api/graphql/project/issues_spec.rb
+61
-0
spec/requests/api/users_spec.rb
spec/requests/api/users_spec.rb
+45
-8
spec/requests/profiles/notifications_controller_spec.rb
spec/requests/profiles/notifications_controller_spec.rb
+2
-3
spec/services/merge_requests/create_pipeline_service_spec.rb
spec/services/merge_requests/create_pipeline_service_spec.rb
+22
-3
spec/services/merge_requests/create_service_spec.rb
spec/services/merge_requests/create_service_spec.rb
+1
-0
spec/services/merge_requests/refresh_service_spec.rb
spec/services/merge_requests/refresh_service_spec.rb
+4
-0
No files found.
CHANGELOG.md
View file @
477c2c26
...
...
@@ -2,18 +2,6 @@
documentation
](
doc/development/changelog.md
)
for instructions on adding your own
entry.
## 13.3.5 (2020-09-04)
### Fixed (6 changes)
-
Coerce string object storage options to booleans. !39901
-
Fix Jira importer user mapping limit. !40310
-
Fix auto-deploy-image external chart dependencies. !40730
-
Fix ActiveRecord::IrreversibleOrderError during restore from backup. !40789
-
Fix wrong caching logic in ProcessRefChangesService. !40821
-
Update the 2FA user update check to account for rounding errors. !41327
## 13.3.4 (2020-09-02)
### Security (1 change)
...
...
@@ -601,14 +589,6 @@ entry.
-
Replace fa-pencil icon with GitLab SVG. !39648
## 13.2.9 (2020-09-04)
### Fixed (2 changes)
-
Fix ActiveRecord::IrreversibleOrderError during restore from backup. !40789
-
Update the 2FA user update check to account for rounding errors. !41327
## 13.2.8 (2020-09-02)
### Security (1 change)
...
...
app/assets/javascripts/clusters/clusters_bundle.js
View file @
477c2c26
...
...
@@ -237,7 +237,7 @@ export default class Clusters {
}
addBannerCloseHandler
(
el
,
status
)
{
el
.
querySelector
(
'
.js-close
-banner
'
).
addEventListener
(
'
click
'
,
()
=>
{
el
.
querySelector
(
'
.js-close
'
).
addEventListener
(
'
click
'
,
()
=>
{
el
.
classList
.
add
(
'
hidden
'
);
this
.
setBannerDismissedState
(
status
,
true
);
});
...
...
app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_utils.js
View file @
477c2c26
import
{
isEmpty
}
from
'
lodash
'
;
import
{
queryToObject
}
from
'
~/lib/utils/url_utility
'
;
/**
* Strips enclosing quotations from a string if it has one.
*
...
...
@@ -29,3 +32,133 @@ export const uniqueTokens = tokens => {
return
uniques
;
},
[]);
};
/**
* Creates a token from a type and a filter. Example returned object
* { type: 'myType', value: { data: 'myData', operator: '= '} }
* @param {String} type the name of the filter
* @param {Object}
* @param {Object.value} filter value to be returned as token data
* @param {Object.operator} filter operator to be retuned as token operator
* @return {Object}
* @return {Object.type} token type
* @return {Object.value} token value
*/
function
createToken
(
type
,
filter
)
{
return
{
type
,
value
:
{
data
:
filter
.
value
,
operator
:
filter
.
operator
}
};
}
/**
* This function takes a filter object and translates it into a token array
* @param {Object} filters
* @param {Object.myFilterName} a single filter value or an array of filters
* @return {Array} tokens an array of tokens created from filter values
*/
export
function
prepareTokens
(
filters
=
{})
{
return
Object
.
keys
(
filters
).
reduce
((
memo
,
key
)
=>
{
const
value
=
filters
[
key
];
if
(
!
value
)
{
return
memo
;
}
if
(
Array
.
isArray
(
value
))
{
return
[...
memo
,
...
value
.
map
(
filterValue
=>
createToken
(
key
,
filterValue
))];
}
return
[...
memo
,
createToken
(
key
,
value
)];
},
[]);
}
export
function
processFilters
(
filters
)
{
return
filters
.
reduce
((
acc
,
token
)
=>
{
const
{
type
,
value
}
=
token
;
const
{
operator
}
=
value
;
const
tokenValue
=
value
.
data
;
if
(
!
acc
[
type
])
{
acc
[
type
]
=
[];
}
acc
[
type
].
push
({
value
:
tokenValue
,
operator
});
return
acc
;
},
{});
}
/**
* This function takes a filter object and maps it into a query object. Example filter:
* { myFilterName: { value: 'foo', operator: '=' } }
* gets translated into:
* { myFilterName: 'foo', 'not[myFilterName]': null }
* @param {Object} filters
* @param {Object.myFilterName} a single filter value or an array of filters
* @return {Object} query object with both filter name and not-name with values
*/
export
function
filterToQueryObject
(
filters
=
{})
{
return
Object
.
keys
(
filters
).
reduce
((
memo
,
key
)
=>
{
const
filter
=
filters
[
key
];
let
selected
;
let
unselected
;
if
(
Array
.
isArray
(
filter
))
{
selected
=
filter
.
filter
(
item
=>
item
.
operator
===
'
=
'
).
map
(
item
=>
item
.
value
);
unselected
=
filter
.
filter
(
item
=>
item
.
operator
===
'
!=
'
).
map
(
item
=>
item
.
value
);
}
else
{
selected
=
filter
?.
operator
===
'
=
'
?
filter
.
value
:
null
;
unselected
=
filter
?.
operator
===
'
!=
'
?
filter
.
value
:
null
;
}
if
(
isEmpty
(
selected
))
{
selected
=
null
;
}
if
(
isEmpty
(
unselected
))
{
unselected
=
null
;
}
return
{
...
memo
,
[
key
]:
selected
,
[
`not[
${
key
}
]`
]:
unselected
};
},
{});
}
/**
* Extracts filter name from url name, e.g. `not[my_filter]` => `my_filter`
* and returns the operator with it depending on the filter name
* @param {String} filterName from url
* @return {Object}
* @return {Object.filterName} extracted filtern ame
* @return {Object.operator} `=` or `!=`
*/
function
extractNameAndOperator
(
filterName
)
{
// eslint-disable-next-line @gitlab/require-i18n-strings
if
(
filterName
.
startsWith
(
'
not[
'
)
&&
filterName
.
endsWith
(
'
]
'
))
{
return
{
filterName
:
filterName
.
slice
(
4
,
-
1
),
operator
:
'
!=
'
};
}
return
{
filterName
,
operator
:
'
=
'
};
}
/**
* This function takes a URL query string and maps it into a filter object. Example query string:
* '?myFilterName=foo'
* gets translated into:
* { myFilterName: { value: 'foo', operator: '=' } }
* @param {String} query URL quert string, e.g. from `window.location.search`
* @return {Object} filter object with filter names and their values
*/
export
function
urlQueryToFilter
(
query
=
''
)
{
const
filters
=
queryToObject
(
query
,
{
gatherArrays
:
true
});
return
Object
.
keys
(
filters
).
reduce
((
memo
,
key
)
=>
{
const
value
=
filters
[
key
];
if
(
!
value
)
{
return
memo
;
}
const
{
filterName
,
operator
}
=
extractNameAndOperator
(
key
);
let
previousValues
=
[];
if
(
Array
.
isArray
(
memo
[
filterName
]))
{
previousValues
=
memo
[
filterName
];
}
if
(
Array
.
isArray
(
value
))
{
const
newAdditions
=
value
.
filter
(
Boolean
).
map
(
item
=>
({
value
:
item
,
operator
}));
return
{
...
memo
,
[
filterName
]:
[...
previousValues
,
...
newAdditions
]
};
}
return
{
...
memo
,
[
filterName
]:
{
value
,
operator
}
};
},
{});
}
app/assets/javascripts/vue_shared/components/rich_content_editor/services/build_html_to_markdown_renderer.js
View file @
477c2c26
...
...
@@ -29,6 +29,7 @@ const buildHTMLToMarkdownRender = (baseRenderer, formattingPreferences = {}) =>
const
emphasisNode
=
'
EM, I
'
;
const
strongNode
=
'
STRONG, B
'
;
const
headingNode
=
'
H1, H2, H3, H4, H5, H6
'
;
const
preCodeNode
=
'
PRE CODE
'
;
return
{
TEXT_NODE
(
node
)
{
...
...
@@ -91,6 +92,13 @@ const buildHTMLToMarkdownRender = (baseRenderer, formattingPreferences = {}) =>
return
attributeDefinition
?
`
${
result
.
trimRight
()}
\n
${
attributeDefinition
}
\n\n`
:
result
;
},
[
preCodeNode
](
node
,
subContent
)
{
const
isReferenceDefinition
=
Boolean
(
node
.
dataset
.
sseReferenceDefinition
);
return
isReferenceDefinition
?
`\n\n
${
node
.
innerText
}
\n`
:
baseRenderer
.
convert
(
node
,
subContent
);
},
};
};
...
...
app/assets/javascripts/vue_shared/components/rich_content_editor/services/renderers/render_identifier_paragraph.js
View file @
477c2c26
import
{
renderUneditableBranch
as
render
}
from
'
./render_utils
'
;
const
identifierRegex
=
/
(
^
\[
.+
\]
: .+
)
/
;
const
isIdentifier
=
text
=>
{
...
...
@@ -10,4 +8,33 @@ const canRender = (node, context) => {
return
isIdentifier
(
context
.
getChildrenText
(
node
));
};
const
getReferenceDefinitions
=
(
node
,
definitions
=
''
)
=>
{
if
(
!
node
)
{
return
definitions
;
}
const
definition
=
node
.
type
===
'
text
'
?
node
.
literal
:
'
\n
'
;
return
getReferenceDefinitions
(
node
.
next
,
`
${
definitions
}${
definition
}
`
);
};
const
render
=
(
node
,
{
skipChildren
})
=>
{
const
content
=
getReferenceDefinitions
(
node
.
firstChild
);
skipChildren
();
return
[
{
type
:
'
openTag
'
,
tagName
:
'
pre
'
,
classNames
:
[
'
code-block
'
,
'
language-markdown
'
],
attributes
:
{
'
data-sse-reference-definition
'
:
true
},
},
{
type
:
'
openTag
'
,
tagName
:
'
code
'
},
{
type
:
'
text
'
,
content
},
{
type
:
'
closeTag
'
,
tagName
:
'
code
'
},
{
type
:
'
closeTag
'
,
tagName
:
'
pre
'
},
];
};
export
default
{
canRender
,
render
};
app/controllers/admin/users_controller.rb
View file @
477c2c26
...
...
@@ -149,7 +149,7 @@ def update
password_confirmation:
params
[
:user
][
:password_confirmation
]
}
password_params
[
:password_expires_at
]
=
Time
.
current
unless
changing_own_password
?
password_params
[
:password_expires_at
]
=
Time
.
current
if
admin_making_changes_for_another_user
?
user_params_with_pass
.
merge!
(
password_params
)
end
...
...
@@ -157,6 +157,7 @@ def update
respond_to
do
|
format
|
result
=
Users
::
UpdateService
.
new
(
current_user
,
user_params_with_pass
.
merge
(
user:
user
)).
execute
do
|
user
|
user
.
skip_reconfirmation!
user
.
send_only_admin_changed_your_password_notification!
if
admin_making_changes_for_another_user?
end
if
result
[
:status
]
==
:success
...
...
@@ -197,8 +198,8 @@ def remove_email
protected
def
changing_own_password
?
user
=
=
current_user
def
admin_making_changes_for_another_user
?
user
!
=
current_user
end
def
user
...
...
app/controllers/profiles/notifications_controller.rb
View file @
477c2c26
# frozen_string_literal: true
class
Profiles::NotificationsController
<
Profiles
::
ApplicationController
NOTIFICATIONS_PER_PAGE
=
10
# rubocop: disable CodeReuse/ActiveRecord
def
show
@user
=
current_user
@user_groups
=
user_groups
@group_notifications
=
u
ser
_g
roup
s
.
map
{
|
group
|
current_user
.
n
otification
_s
ettings
_for
(
group
,
inherit:
true
)
}
@group_notifications
=
U
ser
G
roup
N
otification
S
ettings
Finder
.
new
(
current_user
,
user_groups
).
execute
@project_notifications
=
current_user
.
notification_settings
.
for_projects
.
order
(
:id
)
.
preload_source_route
...
...
@@ -35,6 +33,6 @@ def user_params
private
def
user_groups
GroupsFinder
.
new
(
current_user
,
all_available:
false
).
execute
.
order_name_asc
.
page
(
params
[
:page
])
.
per
(
NOTIFICATIONS_PER_PAGE
)
GroupsFinder
.
new
(
current_user
,
all_available:
false
).
execute
.
order_name_asc
.
page
(
params
[
:page
])
end
end
app/finders/user_group_notification_settings_finder.rb
0 → 100644
View file @
477c2c26
# frozen_string_literal: true
class
UserGroupNotificationSettingsFinder
def
initialize
(
user
,
groups
)
@user
=
user
@groups
=
groups
end
def
execute
groups_with_ancestors
=
Gitlab
::
ObjectHierarchy
.
new
(
groups
).
base_and_ancestors
@loaded_groups_with_ancestors
=
groups_with_ancestors
.
index_by
(
&
:id
)
@loaded_notification_settings
=
user
.
notification_settings_for_groups
(
groups_with_ancestors
).
preload_source_route
.
index_by
(
&
:source_id
)
groups
.
map
do
|
group
|
find_notification_setting_for
(
group
)
end
end
private
attr_reader
:user
,
:groups
,
:loaded_groups_with_ancestors
,
:loaded_notification_settings
def
find_notification_setting_for
(
group
)
return
loaded_notification_settings
[
group
.
id
]
if
loaded_notification_settings
[
group
.
id
]
return
user
.
notification_settings
.
build
(
source:
group
)
if
group
.
parent_id
.
nil?
parent_setting
=
loaded_notification_settings
[
group
.
parent_id
]
if
should_copy?
(
parent_setting
)
user
.
notification_settings
.
build
(
source:
group
)
do
|
ns
|
ns
.
assign_attributes
(
parent_setting
.
slice
(
*
NotificationSetting
.
allowed_fields
))
end
else
find_notification_setting_for
(
loaded_groups_with_ancestors
[
group
.
parent_id
])
end
end
def
should_copy?
(
parent_setting
)
return
false
unless
parent_setting
parent_setting
.
level
!=
NotificationSetting
.
levels
[
:global
]
||
parent_setting
.
notification_email
.
present?
end
end
app/graphql/resolvers/concerns/looks_ahead.rb
View file @
477c2c26
...
...
@@ -46,7 +46,7 @@ def node_selection
if
lookahead
.
selects?
(
:nodes
)
lookahead
.
selection
(
:nodes
)
elsif
lookahead
.
selects?
(
:edges
)
lookahead
.
selection
(
:edges
).
selection
(
:node
s
)
lookahead
.
selection
(
:edges
).
selection
(
:node
)
end
end
end
app/graphql/resolvers/issues_resolver.rb
View file @
477c2c26
...
...
@@ -34,7 +34,8 @@ def continue_issue_resolve(parent, finder, **args)
def
preloads
{
alert_management_alert:
[
:alert_management_alert
]
alert_management_alert:
[
:alert_management_alert
],
labels:
[
:labels
]
}
end
...
...
app/graphql/types/issue_type.rb
View file @
477c2c26
...
...
@@ -42,8 +42,7 @@ class IssueType < BaseObject
field
:assignees
,
Types
::
UserType
.
connection_type
,
null:
true
,
complexity:
5
,
description:
'Assignees of the issue'
# Remove complexity when BatchLoader is used
field
:labels
,
Types
::
LabelType
.
connection_type
,
null:
true
,
complexity:
5
,
field
:labels
,
Types
::
LabelType
.
connection_type
,
null:
true
,
description:
'Labels of the issue'
field
:milestone
,
Types
::
MilestoneType
,
null:
true
,
description:
'Milestone of the issue'
,
...
...
app/helpers/emails_helper.rb
View file @
477c2c26
...
...
@@ -181,6 +181,10 @@ def say_hi(user)
_
(
'Hi %{username}!'
)
%
{
username:
sanitize_name
(
user
.
name
)
}
end
def
say_hello
(
user
)
_
(
'Hello, %{username}!'
)
%
{
username:
sanitize_name
(
user
.
name
)
}
end
def
two_factor_authentication_disabled_text
_
(
'Two-factor authentication has been disabled for your GitLab account.'
)
end
...
...
@@ -190,7 +194,7 @@ def re_enable_two_factor_authentication_text(format: nil)
case
format
when
:html
settings_link_to
=
link
_to
(
_
(
'two-factor authentication settings'
),
url
,
target: :_blank
,
rel:
'noopener noreferrer'
).
html_safe
settings_link_to
=
generate_
link
(
_
(
'two-factor authentication settings'
),
url
).
html_safe
_
(
"If you want to re-enable two-factor authentication, visit the %{settings_link_to} page."
).
html_safe
%
{
settings_link_to:
settings_link_to
}
else
_
(
'If you want to re-enable two-factor authentication, visit %{two_factor_link}'
)
%
...
...
@@ -198,8 +202,28 @@ def re_enable_two_factor_authentication_text(format: nil)
end
end
def
admin_changed_password_text
(
format:
nil
)
url
=
Gitlab
.
config
.
gitlab
.
url
case
format
when
:html
link_to
=
generate_link
(
url
,
url
).
html_safe
_
(
'An administrator changed the password for your GitLab account on %{link_to}.'
).
html_safe
%
{
link_to:
link_to
}
else
_
(
'An administrator changed the password for your GitLab account on %{link_to}.'
)
%
{
link_to:
url
}
end
end
def
contact_your_administrator_text
_
(
'Please contact your administrator with any questions.'
)
end
private
def
generate_link
(
text
,
url
)
link_to
(
text
,
url
,
target: :_blank
,
rel:
'noopener noreferrer'
)
end
def
show_footer?
email_header_and_footer_enabled?
&&
current_appearance
&
.
show_footer?
end
...
...
app/mailers/devise_mailer.rb
View file @
477c2c26
...
...
@@ -9,6 +9,10 @@ class DeviseMailer < Devise::Mailer
helper
EmailsHelper
helper
ApplicationHelper
def
password_change_by_admin
(
record
,
opts
=
{})
devise_mail
(
record
,
:password_change_by_admin
,
opts
)
end
protected
def
subject_for
(
key
)
...
...
app/models/concerns/admin_changed_password_notifier.rb
0 → 100644
View file @
477c2c26
# frozen_string_literal: true
module
AdminChangedPasswordNotifier
# This module is responsible for triggering the `Password changed by administrator` emails
# when a GitLab administrator changes the password of another user.
# Usage
# These emails are disabled by default and are never trigerred after updating the password, unless
# explicitly specified.
# To explicitly trigger this email, the `send_only_admin_changed_your_password_notification!`
# method should be called, so like:
# user = User.find_by(email: 'hello@example.com')
# user.send_only_admin_changed_your_password_notification!
# user.password = user.password_confirmation = 'new_password'
# user.save!
# The `send_only_admin_changed_your_password_notification` has 2 responsibilities.
# It prevents triggering Devise's default `Password changed` email.
# It trigggers the `Password changed by administrator` email.
# It is important to skip sending the default Devise email when sending out `Password changed by administrator`
# email because we should not be sending 2 emails for the same event,
# hence the only public API made available from this module is `send_only_admin_changed_your_password_notification!`
# There is no public API made available to send the `Password changed by administrator` email,
# *without* skipping the default `Password changed` email, to prevent the problem mentioned above.
extend
ActiveSupport
::
Concern
included
do
after_update
:send_admin_changed_your_password_notification
,
if: :send_admin_changed_your_password_notification?
end
def
initialize
(
*
args
,
&
block
)
@allow_admin_changed_your_password_notification
=
false
# These emails are off by default
super
end
def
send_only_admin_changed_your_password_notification!
skip_password_change_notification!
# skip sending the default Devise 'password changed' notification
allow_admin_changed_your_password_notification!
end
private
def
send_admin_changed_your_password_notification
send_devise_notification
(
:password_change_by_admin
)
end
def
allow_admin_changed_your_password_notification!
@allow_admin_changed_your_password_notification
=
true
# rubocop:disable Gitlab/ModuleWithInstanceVariables
end
def
send_admin_changed_your_password_notification?
self
.
class
.
send_password_change_notification
&&
saved_change_to_encrypted_password?
&&
@allow_admin_changed_your_password_notification
# rubocop:disable Gitlab/ModuleWithInstanceVariables
end
end
app/models/issue.rb
View file @
477c2c26
...
...
@@ -73,7 +73,8 @@ def most_recent
enum
issue_type:
{
issue:
0
,
incident:
1
incident:
1
,
test_case:
2
## EE-only
}
alias_attribute
:parent_ids
,
:project_id
...
...
app/models/user.rb
View file @
477c2c26
...
...
@@ -58,6 +58,8 @@ class User < ApplicationRecord
devise
:lockable
,
:recoverable
,
:rememberable
,
:trackable
,
:validatable
,
:omniauthable
,
:confirmable
,
:registerable
include
AdminChangedPasswordNotifier
# This module adds async behaviour to Devise emails
# and should be added after Devise modules are initialized.
include
AsyncDeviseEmail
...
...
@@ -1461,6 +1463,11 @@ def notification_settings_for(source, inherit: false)
end
end
def
notification_settings_for_groups
(
groups
)
ids
=
groups
.
is_a?
(
ActiveRecord
::
Relation
)
?
groups
.
select
(
:id
)
:
groups
.
map
(
&
:id
)
notification_settings
.
for_groups
.
where
(
source_id:
ids
)
end
# Lazy load global notification setting
# Initializes User setting with Participating level if setting not persisted
def
global_notification_setting
...
...
app/services/auto_merge/base_service.rb
View file @
477c2c26
...
...
@@ -60,6 +60,21 @@ def available_for?(merge_request)
end
end
##
# NOTE: This method is to be removed when `disallow_to_create_merge_request_pipelines_in_target_project`
# feature flag is removed.
def
self
.
can_add_to_merge_train?
(
merge_request
)
if
Gitlab
::
Ci
::
Features
.
disallow_to_create_merge_request_pipelines_in_target_project?
(
merge_request
.
target_project
)
merge_request
.
for_same_project?
else
true
end
end
def
can_add_to_merge_train?
(
merge_request
)
self
.
class
.
can_add_to_merge_train?
(
merge_request
)
end
private
# Overridden in child classes
...
...
app/services/merge_requests/create_pipeline_service.rb
View file @
477c2c26
...
...
@@ -48,12 +48,18 @@ def pipeline_ref_for_detached_merge_request_pipeline(m