summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diff_notes/components/jump_to_discussion.js2
-rw-r--r--app/assets/javascripts/diffs/store/getters.js2
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_emoji.js11
-rw-r--r--app/assets/javascripts/init_legacy_filters.js14
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js11
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue2
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js10
-rw-r--r--app/assets/javascripts/pages/dashboard/merge_requests/index.js12
-rw-r--r--app/assets/javascripts/pages/users/user_overview_block.js5
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js110
-rw-r--r--app/assets/javascripts/search_autocomplete.js9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue9
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue2
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/concerns/issuable_collections.rb36
-rw-r--r--app/controllers/concerns/merge_requests_action.rb2
-rw-r--r--app/controllers/dashboard_controller.rb12
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb11
-rw-r--r--app/controllers/root_controller.rb4
-rw-r--r--app/finders/events_finder.rb2
-rw-r--r--app/finders/group_descendants_finder.rb2
-rw-r--r--app/finders/issuable_finder.rb14
-rw-r--r--app/helpers/application_helper.rb12
-rw-r--r--app/helpers/auth_helper.rb17
-rw-r--r--app/helpers/dashboard_helper.rb4
-rw-r--r--app/helpers/search_helper.rb15
-rw-r--r--app/models/ci/build.rb28
-rw-r--r--app/models/clusters/kubernetes_namespace.rb37
-rw-r--r--app/models/commit.rb25
-rw-r--r--app/models/concerns/avatarable.rb2
-rw-r--r--app/models/member.rb24
-rw-r--r--app/models/project_services/chat_message/push_message.rb47
-rw-r--r--app/models/user.rb49
-rw-r--r--app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb2
-rw-r--r--app/services/projects/disable_deploy_key_service.rb13
-rw-r--r--app/services/projects/enable_deploy_key_service.rb14
-rw-r--r--app/services/todos/destroy/entity_leave_service.rb2
-rw-r--r--app/services/todos/destroy/private_features_service.rb6
-rw-r--r--app/services/users/build_service.rb2
-rw-r--r--app/views/dashboard/issues.html.haml4
-rw-r--r--app/views/dashboard/merge_requests.html.haml4
-rw-r--r--app/views/devise/shared/_signin_box.html.haml6
-rw-r--r--app/views/devise/shared/_tabs_ldap.html.haml7
-rw-r--r--app/views/shared/_labels_row.html.haml5
-rw-r--r--app/views/shared/issuable/_filter.html.haml32
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml5
-rw-r--r--app/views/users/_overview.html.haml40
-rw-r--r--app/views/users/show.html.haml6
48 files changed, 350 insertions, 344 deletions
diff --git a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
index c0c21416275..8542a6e718a 100644
--- a/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
+++ b/app/assets/javascripts/diff_notes/components/jump_to_discussion.js
@@ -112,7 +112,7 @@ const JumpToDiscussion = Vue.extend({
if (!hasDiscussionsToJumpTo) {
// If there are no discussions to jump to on the current page,
- // switch to the notes tab and jump to the first disucssion there.
+ // switch to the notes tab and jump to the first discussion there.
window.mrTabs.activateTab('show');
activeTab = 'show';
jumpToFirstDiscussion = true;
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index 05e32e3c1f1..6a87b712b48 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -23,7 +23,7 @@ export const diffHasAllExpandedDiscussions = (state, getters) => diff => {
};
/**
- * Checks if the diff has all discussions collpased
+ * Checks if the diff has all discussions collapsed
* @param {Object} diff
* @returns {Boolean}
*/
diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js
index af7936a92fb..d9a4d06b549 100644
--- a/app/assets/javascripts/filtered_search/dropdown_emoji.js
+++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js
@@ -69,10 +69,13 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
// Replace empty gl-emoji tag to real content
const dropdownItems = [...this.dropdown.querySelectorAll('.filter-dropdown-item')];
dropdownItems.forEach(dropdownItem => {
- const name = dropdownItem.querySelector('.js-data-value').innerText;
- const emojiTag = this.glEmojiTag(name);
- const emojiElement = dropdownItem.querySelector('gl-emoji');
- emojiElement.outerHTML = emojiTag;
+ const valueElement = dropdownItem.querySelector('.js-data-value');
+ if (valueElement !== null) {
+ const name = valueElement.innerText;
+ const emojiTag = this.glEmojiTag(name);
+ const emojiElement = dropdownItem.querySelector('gl-emoji');
+ emojiElement.outerHTML = emojiTag;
+ }
});
}
diff --git a/app/assets/javascripts/init_legacy_filters.js b/app/assets/javascripts/init_legacy_filters.js
deleted file mode 100644
index b6ff97d1279..00000000000
--- a/app/assets/javascripts/init_legacy_filters.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/* eslint-disable no-new */
-import LabelsSelect from './labels_select';
-import subscriptionSelect from './subscription_select';
-import UsersSelect from './users_select';
-import issueStatusSelect from './issue_status_select';
-import MilestoneSelect from './milestone_select';
-
-export default () => {
- new UsersSelect();
- new LabelsSelect();
- new MilestoneSelect();
- issueStatusSelect();
- subscriptionSelect();
-};
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index c52cfb806a2..3618c6af7e2 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -39,7 +39,7 @@ function blockTagText(text, textArea, blockTag, selected) {
}
}
-function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
+function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, select }) {
var pos;
if (!textArea.setSelectionRange) {
return;
@@ -51,7 +51,7 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
return textArea.setSelectionRange(startPosition, endPosition);
}
if (textArea.selectionStart === textArea.selectionEnd) {
- if (wrapped) {
+ if (positionBetweenTags) {
pos = textArea.selectionStart - tag.length;
} else {
pos = textArea.selectionStart;
@@ -67,7 +67,6 @@ function moveCursor({ textArea, tag, wrapped, removedLastNewLine, select }) {
export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) {
var textToInsert,
- inserted,
selectedSplit,
startChar,
removedLastNewLine,
@@ -155,7 +154,7 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr
return moveCursor({
textArea,
tag: tag.replace(textPlaceholder, selected),
- wrap,
+ positionBetweenTags: wrap && selected.length === 0,
removedLastNewLine,
select,
});
@@ -171,10 +170,6 @@ function updateText({ textArea, tag, blockTag, wrap, select }) {
return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select });
}
-function replaceRange(s, start, end, substitute) {
- return s.substring(0, start) + substitute + s.substring(end);
-}
-
export function addMarkdownListeners(form) {
return $('.js-md', form)
.off('click')
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index d9f8604ed10..bd0bcc0d819 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -22,7 +22,7 @@ export default {
},
output: {
type: Object,
- requred: true,
+ required: true,
default: () => ({}),
},
},
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index c4901dd1cb6..9055738f86e 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -1,7 +1,13 @@
import projectSelect from '~/project_select';
-import initLegacyFilters from '~/init_legacy_filters';
+import initFilteredSearch from '~/pages/search/init_filtered_search';
+import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
+import { FILTERED_SEARCH } from '~/pages/constants';
document.addEventListener('DOMContentLoaded', () => {
+ initFilteredSearch({
+ page: FILTERED_SEARCH.ISSUES,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ });
+
projectSelect();
- initLegacyFilters();
});
diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
index c4901dd1cb6..260484726f3 100644
--- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js
+++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
@@ -1,7 +1,15 @@
import projectSelect from '~/project_select';
-import initLegacyFilters from '~/init_legacy_filters';
+import initFilteredSearch from '~/pages/search/init_filtered_search';
+import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
+import { FILTERED_SEARCH } from '~/pages/constants';
document.addEventListener('DOMContentLoaded', () => {
+ IssuableFilteredSearchTokenKeys.addExtraTokensForMergeRequests();
+
+ initFilteredSearch({
+ page: FILTERED_SEARCH.MERGE_REQUESTS,
+ filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ });
+
projectSelect();
- initLegacyFilters();
});
diff --git a/app/assets/javascripts/pages/users/user_overview_block.js b/app/assets/javascripts/pages/users/user_overview_block.js
index 2ed177be558..eec2b5ca8e5 100644
--- a/app/assets/javascripts/pages/users/user_overview_block.js
+++ b/app/assets/javascripts/pages/users/user_overview_block.js
@@ -10,6 +10,7 @@ export default class UserOverviewBlock {
limit: DEFAULT_LIMIT,
...options.requestParams,
};
+ this.postRenderCallback = options.postRenderCallback;
this.loadData();
}
@@ -43,5 +44,9 @@ export default class UserOverviewBlock {
}
loadingEl.classList.add('hide');
+
+ if (this.postRenderCallback) {
+ this.postRenderCallback.call(this);
+ }
}
}
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 04bcb16f036..aa537d4a43e 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -2,7 +2,8 @@ import $ from 'jquery';
import axios from '~/lib/utils/axios_utils';
import Activities from '~/activities';
import { localTimeAgo } from '~/lib/utils/datetime_utility';
-import { __, sprintf } from '~/locale';
+import AjaxCache from '~/lib/utils/ajax_cache';
+import { __ } from '~/locale';
import flash from '~/flash';
import ActivityCalendar from './activity_calendar';
import UserOverviewBlock from './user_overview_block';
@@ -62,23 +63,20 @@ import UserOverviewBlock from './user_overview_block';
* </div>
*/
-const CALENDAR_TEMPLATES = {
- activity: `
- <div class="clearfix calendar">
- <div class="js-contrib-calendar"></div>
- <div class="calendar-hint bottom-right"></div>
- </div>
- `,
- overview: `
- <div class="clearfix calendar">
- <div class="calendar-hint"></div>
- <div class="js-contrib-calendar prepend-top-20"></div>
- </div>
- `,
-};
+const CALENDAR_TEMPLATE = `
+ <div class="clearfix calendar">
+ <div class="js-contrib-calendar"></div>
+ <div class="calendar-hint bottom-right"></div>
+ </div>
+`;
const CALENDAR_PERIOD_6_MONTHS = 6;
const CALENDAR_PERIOD_12_MONTHS = 12;
+/* computation based on
+ * width = (group + 1) * this.daySizeWithSpace + this.getExtraWidthPadding(group);
+ * (see activity_calendar.js)
+ */
+const OVERVIEW_CALENDAR_BREAKPOINT = 918;
export default class UserTabs {
constructor({ defaultAction, action, parentEl }) {
@@ -105,6 +103,12 @@ export default class UserTabs {
.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event))
.on('click', '.gl-pagination a', event => this.changeProjectsPage(event));
+
+ window.addEventListener('resize', () => this.onResize());
+ }
+
+ onResize() {
+ this.loadActivityCalendar();
}
changeProjectsPage(e) {
@@ -167,8 +171,6 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('activity');
-
// eslint-disable-next-line no-new
new Activities('#activity');
@@ -180,10 +182,10 @@ export default class UserTabs {
return;
}
- this.loadActivityCalendar('overview');
+ this.loadActivityCalendar();
UserTabs.renderMostRecentBlocks('#js-overview .activities-block', {
- requestParams: { limit: 5 },
+ requestParams: { limit: 10 },
});
UserTabs.renderMostRecentBlocks('#js-overview .projects-block', {
requestParams: { limit: 10, skip_pagination: true },
@@ -198,52 +200,39 @@ export default class UserTabs {
container,
url: $(`${container} .overview-content-list`).data('href'),
...options,
+ postRenderCallback: () => localTimeAgo($('.js-timeago', container)),
});
}
- loadActivityCalendar(action) {
- const monthsAgo = action === 'overview' ? CALENDAR_PERIOD_6_MONTHS : CALENDAR_PERIOD_12_MONTHS;
+ loadActivityCalendar() {
const $calendarWrap = this.$parentEl.find('.tab-pane.active .user-calendar');
const calendarPath = $calendarWrap.data('calendarPath');
+
+ AjaxCache.retrieve(calendarPath)
+ .then(data => UserTabs.renderActivityCalendar(data, $calendarWrap))
+ .catch(() => flash(__('There was an error loading users activity calendar.')));
+ }
+
+ static renderActivityCalendar(data, $calendarWrap) {
+ const monthsAgo = UserTabs.getVisibleCalendarPeriod($calendarWrap);
const calendarActivitiesPath = $calendarWrap.data('calendarActivitiesPath');
const utcOffset = $calendarWrap.data('utcOffset');
- let utcFormatted = 'UTC';
- if (utcOffset !== 0) {
- utcFormatted = `UTC${utcOffset > 0 ? '+' : ''}${utcOffset / 3600}`;
- }
+ const calendarHint = __('Issues, merge requests, pushes and comments.');
- axios
- .get(calendarPath)
- .then(({ data }) => {
- $calendarWrap.html(CALENDAR_TEMPLATES[action]);
-
- let calendarHint = '';
-
- if (action === 'activity') {
- calendarHint = sprintf(
- __(
- 'Summary of issues, merge requests, push events, and comments (Timezone: %{utcFormatted})',
- ),
- { utcFormatted },
- );
- } else if (action === 'overview') {
- calendarHint = __('Issues, merge requests, pushes and comments.');
- }
-
- $calendarWrap.find('.calendar-hint').text(calendarHint);
-
- // eslint-disable-next-line no-new
- new ActivityCalendar(
- '.tab-pane.active .js-contrib-calendar',
- '.tab-pane.active .user-calendar-activities',
- data,
- calendarActivitiesPath,
- utcOffset,
- 0,
- monthsAgo,
- );
- })
- .catch(() => flash(__('There was an error loading users activity calendar.')));
+ $calendarWrap.html(CALENDAR_TEMPLATE);
+
+ $calendarWrap.find('.calendar-hint').text(calendarHint);
+
+ // eslint-disable-next-line no-new
+ new ActivityCalendar(
+ '.tab-pane.active .js-contrib-calendar',
+ '.tab-pane.active .user-calendar-activities',
+ data,
+ calendarActivitiesPath,
+ utcOffset,
+ 0,
+ monthsAgo,
+ );
}
toggleLoading(status) {
@@ -267,4 +256,11 @@ export default class UserTabs {
getCurrentAction() {
return this.$parentEl.find('.nav-links a.active').data('action');
}
+
+ static getVisibleCalendarPeriod($calendarWrap) {
+ const width = $calendarWrap.width();
+ return width < OVERVIEW_CALENDAR_BREAKPOINT
+ ? CALENDAR_PERIOD_6_MONTHS
+ : CALENDAR_PERIOD_12_MONTHS;
+ }
}
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index 17def77b2d7..0a4583b5861 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -253,7 +253,6 @@ export class SearchAutocomplete {
}
getCategoryContents() {
- const userId = gon.current_user_id;
const userName = gon.current_username;
const { projectOptions, groupOptions, dashboardOptions } = gl;
@@ -279,21 +278,21 @@ export class SearchAutocomplete {
const issueItems = [
{
text: s__('SearchAutocomplete|Issues assigned to me'),
- url: `${issuesPath}/?assignee_id=${userId}`,
+ url: `${issuesPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Issues I've created"),
- url: `${issuesPath}/?author_id=${userId}`,
+ url: `${issuesPath}/?author_username=${userName}`,
},
];
const mergeRequestItems = [
{
text: s__('SearchAutocomplete|Merge requests assigned to me'),
- url: `${mrPath}/?assignee_id=${userId}`,
+ url: `${mrPath}/?assignee_username=${userName}`,
},
{
text: s__("SearchAutocomplete|Merge requests I've created"),
- url: `${mrPath}/?author_id=${userId}`,
+ url: `${mrPath}/?author_username=${userName}`,
},
];
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
index 4ec925aa8a6..fe741dc60cb 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -33,6 +33,10 @@ export default {
type: Object,
required: true,
},
+ showMetrics: {
+ type: Boolean,
+ required: true,
+ },
},
deployedTextMap: {
running: __('Deploying to'),
@@ -74,6 +78,9 @@ export default {
shouldRenderDropdown() {
return this.deployment.changes && this.deployment.changes.length > 0;
},
+ showMemoryUsage() {
+ return this.hasMetrics && this.showMetrics;
+ },
},
methods: {
stopEnvironment() {
@@ -136,7 +143,7 @@ export default {
{{ deployTimeago }}
</span>
<memory-usage
- v-if="hasMetrics"
+ v-if="showMemoryUsage"
:metrics-url="deployment.metrics_url"
:metrics-monitoring-url="deployment.metrics_monitoring_url"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 063d1e15544..3b840540657 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -312,6 +312,7 @@ export default {
:key="`pre-merge-deploy-${deployment.id}`"
class="js-pre-merge-deploy"
:deployment="deployment"
+ :show-metrics="false"
/>
<div class="mr-section-container">
<grouped-test-reports-app
@@ -366,6 +367,7 @@ export default {
v-for="postMergeDeployment in mr.postMergeDeployments"
:key="`post-merge-deploy-${postMergeDeployment.id}`"
:deployment="postMergeDeployment"
+ :show-metrics="true"
class="js-post-deployment"
/>
</template>
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7f4aa8244ac..b839da7770d 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -181,11 +181,11 @@ class ApplicationController < ActionController::Base
Ability.allowed?(object, action, subject)
end
- def access_denied!(message = nil)
+ def access_denied!(message = nil, status = nil)
# If we display a custom access denied message to the user, we don't want to
# hide existence of the resource, rather tell them they cannot access it using
# the provided message
- status = message.present? ? :forbidden : :not_found
+ status ||= message.present? ? :forbidden : :not_found
respond_to do |format|
format.any { head status }
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 5217b4be928..34a8c50fcbd 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -81,36 +81,36 @@ module IssuableCollections
end
def issuable_finder_for(finder_class)
- finder_class.new(current_user, filter_params)
+ finder_class.new(current_user, finder_options)
end
# rubocop:disable Gitlab/ModuleWithInstanceVariables
- # rubocop: disable CodeReuse/ActiveRecord
- def filter_params
- set_sort_order_from_cookie
- set_default_state
+ def finder_options
+ params[:state] = default_state if params[:state].blank?
- # Skip irrelevant Rails routing params
- @filter_params = params.dup.except(:controller, :action, :namespace_id)
- @filter_params[:sort] ||= default_sort_order
+ options = {
+ scope: params[:scope],
+ state: params[:state],
+ sort: set_sort_order_from_cookie || default_sort_order
+ }
- @sort = @filter_params[:sort]
+ # Used by view to highlight active option
+ @sort = options[:sort]
if @project
- @filter_params[:project_id] = @project.id
+ options[:project_id] = @project.id
elsif @group
- @filter_params[:group_id] = @group.id
- @filter_params[:include_subgroups] = true
- @filter_params[:use_cte_for_search] = true
+ options[:group_id] = @group.id
+ options[:include_subgroups] = true
+ options[:use_cte_for_search] = true
end
- @filter_params.permit(finder_type.valid_params)
+ params.permit(finder_type.valid_params).merge(options)
end
- # rubocop: enable CodeReuse/ActiveRecord
# rubocop:enable Gitlab/ModuleWithInstanceVariables
- def set_default_state
- params[:state] = 'opened' if params[:state].blank?
+ def default_state
+ 'opened'
end
def set_sort_order_from_cookie
@@ -121,7 +121,7 @@ module IssuableCollections
sort_value = update_cookie_value(sort_param)
set_secure_cookie(remember_sorting_key, sort_value)
- params[:sort] = sort_value
+ sort_value
end
def remember_sorting_key
diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb
index 285f2c3a8a0..ed10f32512e 100644
--- a/app/controllers/concerns/merge_requests_action.rb
+++ b/app/controllers/concerns/merge_requests_action.rb
@@ -19,7 +19,7 @@ module MergeRequestsAction
(MergeRequestsFinder if action_name == 'merge_requests')
end
- def filter_params
+ def finder_options
super.merge(non_archived: true)
end
end
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index c032fb2efb5..4ce9be44403 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -4,13 +4,6 @@ class DashboardController < Dashboard::ApplicationController
include IssuesAction
include MergeRequestsAction
- FILTER_PARAMS = [
- :author_id,
- :assignee_id,
- :milestone_title,
- :label_name
- ].freeze
-
before_action :event_filter, only: :activity
before_action :projects, only: [:issues, :merge_requests]
before_action :set_show_full_reference, only: [:issues, :merge_requests]
@@ -51,10 +44,13 @@ class DashboardController < Dashboard::ApplicationController
end
def check_filters_presence!
- @no_filters_set = FILTER_PARAMS.none? { |k| params.key?(k) }
+ @no_filters_set = finder_type.scalar_params.none? { |k| params.key?(k) }
return unless @no_filters_set
+ # Call to set selected `state` and `sort` options in view
+ finder_options
+
respond_to do |format|
format.html { render }
format.atom { head :bad_request }
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 92ef10a9ef5..0a593bd35b6 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -46,7 +46,9 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
def enable
- Projects::EnableDeployKeyService.new(@project, current_user, params).execute
+ key = Projects::EnableDeployKeyService.new(@project, current_user, params).execute
+
+ return render_404 unless key
respond_to do |format|
format.html { redirect_to_repository_settings(@project, anchor: 'js-deploy-keys-settings') }
@@ -54,19 +56,16 @@ class Projects::DeployKeysController < Projects::ApplicationController
end
end
- # rubocop: disable CodeReuse/ActiveRecord
def disable
- deploy_key_project = @project.deploy_keys_projects.find_by(deploy_key_id: params[:id])
- return render_404 unless deploy_key_project
+ deploy_key_project = Projects::DisableDeployKeyService.new(@project, current_user, params).execute
- deploy_key_project.destroy!
+ return render_404 unless deploy_key_project
respond_to do |format|
format.html { redirect_to_repository_settings(@project, anchor: 'js-deploy-keys-settings') }
format.json { head :ok }
end
end
- # rubocop: enable CodeReuse/ActiveRecord
protected
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
index ebf70f25bda..7b6657e1196 100644
--- a/app/controllers/root_controller.rb
+++ b/app/controllers/root_controller.rb
@@ -45,9 +45,9 @@ class RootController < Dashboard::ProjectsController
when 'todos'
redirect_to(dashboard_todos_path)
when 'issues'
- redirect_to(issues_dashboard_path(assignee_id: current_user.id))
+ redirect_to(issues_dashboard_path(assignee_username: current_user.username))
when 'merge_requests'
- redirect_to(merge_requests_dashboard_path(assignee_id: current_user.id))
+ redirect_to(merge_requests_dashboard_path(assignee_username: current_user.username))
end
end
diff --git a/app/finders/events_finder.rb b/app/finders/events_finder.rb
index 2e82bda8730..8df01f1dad9 100644
--- a/app/finders/events_finder.rb
+++ b/app/finders/events_finder.rb
@@ -58,7 +58,7 @@ class EventsFinder
def by_target_type(events)
return events unless Event::TARGET_TYPES[params[:target_type]]
- events.where(target_type: Event::TARGET_TYPES[params[:target_type]])
+ events.where(target_type: Event::TARGET_TYPES[params[:target_type]].name)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb
index c96979619fd..a9ce5be13f3 100644
--- a/app/finders/group_descendants_finder.rb
+++ b/app/finders/group_descendants_finder.rb
@@ -178,7 +178,7 @@ class GroupDescendantsFinder
end
def sort
- params.fetch(:sort, 'id_asc')
+ params.fetch(:sort, 'created_desc')
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 93bef592c65..fdc630cbf72 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -14,7 +14,9 @@
# project_id: integer
# milestone_title: string
# author_id: integer
+# author_username: string
# assignee_id: integer or 'None' or 'Any'
+# assignee_username: string
# search: string
# label_name: string
# sort: string
@@ -49,25 +51,15 @@ class IssuableFinder
assignee_username
author_id
author_username
- authorized_only
- group_id
- iids
label_name
milestone_title
my_reaction_emoji
- non_archived
- project_id
- scope
search
- sort
- state
- include_subgroups
- use_cte_for_search
]
end
def self.array_params
- @array_params ||= { label_name: [], iids: [], assignee_username: [] }
+ @array_params ||= { label_name: [], assignee_username: [] }
end
def self.valid_params
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 4f91e3e4117..74042f0bae8 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -173,17 +173,7 @@ module ApplicationHelper
without = options.delete(:without)
add_label = options.delete(:label)
- exist_opts = {
- state: params[:state],
- scope: params[:scope],
- milestone_title: params[:milestone_title],
- assignee_id: params[:assignee_id],
- author_id: params[:author_id],
- search: params[:search],
- label_name: params[:label_name]
- }
-
- options = exist_opts.merge(options)
+ options = request.query_parameters.merge(options)
if without.present?
without.each do |key|
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index c158cf20dd6..44f85e9c0f8 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -24,6 +24,23 @@ module AuthHelper
Gitlab::Auth::OAuth::Provider.label_for(name)
end
+ def form_based_provider_priority
+ ['crowd', /^ldap/, 'kerberos']
+ end
+
+ def form_based_provider_with_highest_priority
+ @form_based_provider_with_highest_priority ||= begin
+ form_based_provider_priority.each do |provider_regexp|
+ highest_priority = form_based_providers.find { |provider| provider.match?(provider_regexp) }
+ break highest_priority unless highest_priority.nil?
+ end
+ end
+ end
+
+ def form_based_auth_provider_has_active_class?(provider)
+ form_based_provider_with_highest_priority == provider
+ end
+
def form_based_provider?(name)
[LDAP_PROVIDER, 'crowd'].any? { |pattern| pattern === name.to_s }
end
diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb
index 463f4145bdd..d90ef8903a7 100644
--- a/app/helpers/dashboard_helper.rb
+++ b/app/helpers/dashboard_helper.rb
@@ -2,11 +2,11 @@
module DashboardHelper
def assigned_issues_dashboard_path
- issues_dashboard_path(assignee_id: current_user.id)
+ issues_dashboard_path(assignee_username: current_user.username)
end
def assigned_mrs_dashboard_path
- merge_requests_dashboard_path(assignee_id: current_user.id)
+ merge_requests_dashboard_path(assignee_username: current_user.username)
end
def dashboard_nav_links
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 4f9e1322b56..80cc568820a 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -163,15 +163,26 @@ module SearchHelper
if @project.present?
opts[:data]['project-id'] = @project.id
opts[:data]['base-endpoint'] = project_path(@project)
- else
- # Group context
+ elsif @group.present?
opts[:data]['group-id'] = @group.id
opts[:data]['base-endpoint'] = group_canonical_path(@group)
+ else
+ opts[:data]['base-endpoint'] = root_dashboard_path
end
opts
end
+ def search_history_storage_prefix
+ if @project.present?
+ @project.full_path
+ elsif @group.present?
+ @group.full_path
+ else
+ 'dashboard'
+ end
+ end
+
# Sanitize a HTML field for search display. Most tags are stripped out and the
# maximum length is set to 200 characters.
def search_md_sanitize(object, field)
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 889f8ce27a6..d60861dc95f 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -98,7 +98,7 @@ module Ci
scope :matches_tag_ids, -> (tag_ids) do
matcher = ::ActsAsTaggableOn::Tagging
- .where(taggable_type: CommitStatus)
+ .where(taggable_type: CommitStatus.name)
.where(context: 'tags')
.where('taggable_id = ci_builds.id')
.where.not(tag_id: tag_ids).select('1')
@@ -108,7 +108,7 @@ module Ci
scope :with_any_tags, -> do
matcher = ::ActsAsTaggableOn::Tagging
- .where(taggable_type: CommitStatus)
+ .where(taggable_type: CommitStatus.name)
.where(context: 'tags')
.where('taggable_id = ci_builds.id').select('1')
@@ -464,7 +464,9 @@ module Ci
end
def repo_url
- auth = "gitlab-ci-token:#{ensure_token!}@"
+ return unless token
+
+ auth = "gitlab-ci-token:#{token}@"
project.http_url_to_repo.sub(%r{^https?://}) do |prefix|
prefix + auth
end
@@ -725,7 +727,7 @@ module Ci
trace = trace.dup
Gitlab::Ci::MaskSecret.mask!(trace, project.runners_token) if project
- Gitlab::Ci::MaskSecret.mask!(trace, token)
+ Gitlab::Ci::MaskSecret.mask!(trace, token) if token
trace
end
@@ -814,12 +816,12 @@ module Ci
.concat(pipeline.persisted_variables)
.append(key: 'CI_JOB_ID', value: id.to_s)
.append(key: 'CI_JOB_URL', value: Gitlab::Routing.url_helpers.project_job_url(project, self))
- .append(key: 'CI_JOB_TOKEN', value: token, public: false)
+ .append(key: 'CI_JOB_TOKEN', value: token.to_s, public: false)
.append(key: 'CI_BUILD_ID', value: id.to_s)
- .append(key: 'CI_BUILD_TOKEN', value: token, public: false)
+ .append(key: 'CI_BUILD_TOKEN', value: token.to_s, public: false)
.append(key: 'CI_REGISTRY_USER', value: CI_REGISTRY_USER)
- .append(key: 'CI_REGISTRY_PASSWORD', value: token, public: false)
- .append(key: 'CI_REPOSITORY_URL', value: repo_url, public: false)
+ .append(key: 'CI_REGISTRY_PASSWORD', value: token.to_s, public: false)
+ .append(key: 'CI_REPOSITORY_URL', value: repo_url.to_s, public: false)
.concat(deploy_token_variables)
end
end
@@ -831,9 +833,9 @@ module Ci
variables.append(key: 'GITLAB_FEATURES', value: project.licensed_features.join(','))
variables.append(key: 'CI_SERVER_NAME', value: 'GitLab')
variables.append(key: 'CI_SERVER_VERSION', value: Gitlab::VERSION)
- variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: gitlab_version_info.major.to_s)
- variables.append(key: 'CI_SERVER_VERSION_MINOR', value: gitlab_version_info.minor.to_s)
- variables.append(key: 'CI_SERVER_VERSION_PATCH', value: gitlab_version_info.patch.to_s)
+ variables.append(key: 'CI_SERVER_VERSION_MAJOR', value: Gitlab.version_info.major.to_s)
+ variables.append(key: 'CI_SERVER_VERSION_MINOR', value: Gitlab.version_info.minor.to_s)
+ variables.append(key: 'CI_SERVER_VERSION_PATCH', value: Gitlab.version_info.patch.to_s)
variables.append(key: 'CI_SERVER_REVISION', value: Gitlab.revision)
variables.append(key: 'CI_JOB_NAME', value: name)
variables.append(key: 'CI_JOB_STAGE', value: stage)
@@ -850,10 +852,6 @@ module Ci
end
end
- def gitlab_version_info
- @gitlab_version_info ||= Gitlab::VersionInfo.parse(Gitlab::VERSION)
- end
-
def legacy_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables.append(key: 'CI_BUILD_REF', value: sha)
diff --git a/app/models/clusters/kubernetes_namespace.rb b/app/models/clusters/kubernetes_namespace.rb
index cbd52bfb48b..34f5e38ff79 100644
--- a/app/models/clusters/kubernetes_namespace.rb
+++ b/app/models/clusters/kubernetes_namespace.rb
@@ -11,9 +11,13 @@ module Clusters
belongs_to :project, class_name: '::Project'
has_one :platform_kubernetes, through: :cluster
+ before_validation :set_defaults
+
validates :namespace, presence: true
validates :namespace, uniqueness: { scope: :cluster_id }
+ validates :service_account_name, presence: true
+
delegate :ca_pem, to: :platform_kubernetes, allow_nil: true
delegate :api_url, to: :platform_kubernetes, allow_nil: true
@@ -28,38 +32,43 @@ module Clusters
"#{namespace}-token"
end
- def configure_predefined_credentials
- self.namespace = kubernetes_or_project_namespace
- self.service_account_name = default_service_account_name
- end
-
def predefined_variables
config = YAML.dump(kubeconfig)
Gitlab::Ci::Variables::Collection.new.tap do |variables|
variables
- .append(key: 'KUBE_SERVICE_ACCOUNT', value: service_account_name)
- .append(key: 'KUBE_NAMESPACE', value: namespace)
- .append(key: 'KUBE_TOKEN', value: service_account_token, public: false)
+ .append(key: 'KUBE_SERVICE_ACCOUNT', value: service_account_name.to_s)
+ .append(key: 'KUBE_NAMESPACE', value: namespace.to_s)
+ .append(key: 'KUBE_TOKEN', value: service_account_token.to_s, public: false)
.append(key: 'KUBECONFIG', value: config, public: false, file: true)
end
end
- private
-
- def kubernetes_or_project_namespace
- platform_kubernetes&.namespace.presence || project_namespace
+ def set_defaults
+ self.namespace ||= default_platform_kubernetes_namespace
+ self.namespace ||= default_project_namespace
+ self.service_account_name ||= default_service_account_name
end
+ private
+
def default_service_account_name
+ return unless namespace
+
"#{namespace}-service-account"
end
- def project_namespace
- Gitlab::NamespaceSanitizer.sanitize(project_slug)
+ def default_platform_kubernetes_namespace
+ platform_kubernetes&.namespace.presence
+ end
+
+ def default_project_namespace
+ Gitlab::NamespaceSanitizer.sanitize(project_slug) if project_slug
end
def project_slug
+ return unless project
+
"#{project.path}-#{project.id}".downcase
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 9dd0cbacd9e..546fcc54a15 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -230,24 +230,13 @@ class Commit
def lazy_author
BatchLoader.for(author_email.downcase).batch do |emails, loader|
- # A Hash that maps user Emails to the corresponding User objects. The
- # Emails at this point are the _primary_ Emails of the Users.
- users_for_emails = User
- .by_any_email(emails)
- .each_with_object({}) { |user, hash| hash[user.email] = user }
-
- users_for_ids = users_for_emails
- .values
- .each_with_object({}) { |user, hash| hash[user.id] = user }
-
- # Some commits may have used an alternative Email address. In this case we
- # need to query the "emails" table to map those addresses to User objects.
- Email
- .where(email: emails - users_for_emails.keys)
- .pluck(:email, :user_id)
- .each { |(email, id)| users_for_emails[email] = users_for_ids[id] }
-
- users_for_emails.each { |email, user| loader.call(email, user) }
+ users = User.by_any_email(emails).includes(:emails)
+
+ emails.each do |email|
+ user = users.find { |u| u.any_email?(email) }
+
+ loader.call(email, user)
+ end
end
end
diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb
index 0d5311a9985..b42236c1fa2 100644
--- a/app/models/concerns/avatarable.rb
+++ b/app/models/concerns/avatarable.rb
@@ -86,7 +86,7 @@ module Avatarable
params[:model].upload_paths(params[:identifier])
end
- Upload.where(uploader: AvatarUploader, path: paths).find_each do |upload|
+ Upload.where(uploader: AvatarUploader.name, path: paths).find_each do |upload|
model = model_class.instantiate('id' => upload.model_id)
loader.call({ model: model, identifier: File.basename(upload.path) }, upload)
diff --git a/app/models/member.rb b/app/models/member.rb
index 0696ea46c8b..bc8ac14d148 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -152,11 +152,13 @@ class Member < ActiveRecord::Base
return member unless can_update_member?(current_user, member)
- member.attributes = {
- created_by: member.created_by || current_user,
- access_level: access_level,
- expires_at: expires_at
- }
+ set_member_attributes(
+ member,
+ access_level,
+ current_user: current_user,
+ expires_at: expires_at,
+ ldap: ldap
+ )
if member.request?
::Members::ApproveAccessRequestService.new(
@@ -175,6 +177,18 @@ class Member < ActiveRecord::Base
# rubocop: enable CodeReuse/ServiceClass
end
+ # Populates the attributes of a member.
+ #
+ # This logic resides in a separate method so that EE can extend this logic,
+ # without having to patch the `add_user` method directly.
+ def set_member_attributes(member, access_level, current_user: nil, expires_at: nil, ldap: false)
+ member.attributes = {
+ created_by: member.created_by || current_user,
+ access_level: access_level,
+ expires_at: expires_at
+ }
+ end
+
def add_users(source, users, access_level, current_user: nil, expires_at: nil)
return [] unless users.present?
diff --git a/app/models/project_services/chat_message/push_message.rb b/app/models/project_services/chat_message/push_message.rb
index 82be33a12a1..5dd0414b7e6 100644
--- a/app/models/project_services/chat_message/push_message.rb
+++ b/app/models/project_services/chat_message/push_message.rb
@@ -26,16 +26,8 @@ module ChatMessage
end
def activity
- action = if new_branch?
- "created"
- elsif removed_branch?
- "removed"
- else
- "pushed to"
- end
-
{
- title: "#{user_combined_name} #{action} #{ref_type}",
+ title: humanized_action(short: true),
subtitle: "in #{project_link}",
text: compare_link,
image: user_avatar
@@ -44,32 +36,21 @@ module ChatMessage
private
+ def humanized_action(short: false)
+ action, ref_link, target_link = compose_action_details
+ text = [user_combined_name, action, ref_type, ref_link]
+ text << target_link unless short
+ text.join(' ')
+ end
+
def message
- if new_branch?
- new_branch_message
- elsif removed_branch?
- removed_branch_message
- else
- push_message
- end
+ humanized_action
end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
end
- def new_branch_message
- "#{user_combined_name} pushed new #{ref_type} #{branch_link} to #{project_link}"
- end
-
- def removed_branch_message
- "#{user_combined_name} removed #{ref_type} #{ref} from #{project_link}"
- end
-
- def push_message
- "#{user_combined_name} pushed to #{ref_type} #{branch_link} of #{project_link} (#{compare_link})"
- end
-
def commit_messages
commits.map { |commit| compose_commit_message(commit) }.join("\n\n")
end
@@ -115,6 +96,16 @@ module ChatMessage
"[Compare changes](#{compare_url})"
end
+ def compose_action_details
+ if new_branch?
+ ['pushed new', branch_link, "to #{project_link}"]
+ elsif removed_branch?
+ ['removed', ref, "from #{project_link}"]
+ else
+ ['pushed to', branch_link, "of #{project_link} (#{compare_link})"]
+ end
+ end
+
def attachment_color
'#345'
end
diff --git a/app/models/user.rb b/app/models/user.rb
index a400058e87e..01eba7e0426 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -349,20 +349,28 @@ class User < ActiveRecord::Base
def find_by_any_email(email, confirmed: false)
return unless email
- downcased = email.downcase
-
- find_by_private_commit_email(downcased) || by_any_email(downcased, confirmed: confirmed).take
+ by_any_email(email, confirmed: confirmed).take
end
- # Returns a relation containing all the users for the given Email address
- def by_any_email(email, confirmed: false)
- users = where(email: email)
- users = users.confirmed if confirmed
+ # Returns a relation containing all the users for the given email addresses
+ #
+ # @param emails [String, Array<String>] email addresses to check
+ # @param confirmed [Boolean] Only return users where the email is confirmed
+ def by_any_email(emails, confirmed: false)
+ emails = Array(emails).map(&:downcase)
+
+ from_users = where(email: emails)
+ from_users = from_users.confirmed if confirmed
- emails = joins(:emails).where(emails: { email: email })
- emails = emails.confirmed if confirmed
+ from_emails = joins(:emails).where(emails: { email: emails })
+ from_emails = from_emails.confirmed if confirmed
- from_union([users, emails])
+ items = [from_users, from_emails]
+
+ user_ids = Gitlab::PrivateCommitEmail.user_ids_for_emails(emails)
+ items << where(id: user_ids) if user_ids.present?
+
+ from_union(items)
end
def find_by_private_commit_email(email)
@@ -1031,6 +1039,7 @@ class User < ActiveRecord::Base
def all_emails
all_emails = []
all_emails << email unless temp_oauth_email?
+ all_emails << private_commit_email
all_emails.concat(emails.map(&:email))
all_emails
end
@@ -1043,16 +1052,24 @@ class User < ActiveRecord::Base
verified_emails
end
+ def any_email?(check_email)
+ downcased = check_email.downcase
+
+ # handle the outdated private commit email case
+ return true if persisted? &&
+ id == Gitlab::PrivateCommitEmail.user_id_for_email(downcased)
+
+ all_emails.include?(check_email.downcase)
+ end
+
def verified_email?(check_email)
downcased = check_email.downcase
- if email == downcased
- primary_email_verified?
- else
- user_id = Gitlab::PrivateCommitEmail.user_id_for_email(downcased)
+ # handle the outdated private commit email case
+ return true if persisted? &&
+ id == Gitlab::PrivateCommitEmail.user_id_for_email(downcased)
- user_id == id || emails.confirmed.where(email: downcased).exists?
- end
+ verified_emails.include?(check_email.downcase)
end
def hook_attrs
diff --git a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
index 2b607681082..b31426556f6 100644
--- a/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
+++ b/app/services/clusters/gcp/kubernetes/create_or_update_namespace_service.rb
@@ -23,7 +23,7 @@ module Clusters
attr_reader :cluster, :kubernetes_namespace, :platform
def configure_kubernetes_namespace
- kubernetes_namespace.configure_predefined_credentials
+ kubernetes_namespace.set_defaults
end
def create_project_service_account
diff --git a/app/services/projects/disable_deploy_key_service.rb b/app/services/projects/disable_deploy_key_service.rb
new file mode 100644
index 00000000000..e483c0708c4
--- /dev/null
+++ b/app/services/projects/disable_deploy_key_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Projects
+ class DisableDeployKeyService < BaseService
+ def execute
+ # rubocop: disable CodeReuse/ActiveRecord
+ deploy_key_project = project.deploy_keys_projects.find_by(deploy_key_id: params[:id])
+ # rubocop: enable CodeReuse/ActiveRecord
+
+ deploy_key_project&.destroy!
+ end
+ end
+end
diff --git a/app/services/projects/enable_deploy_key_service.rb b/app/services/projects/enable_deploy_key_service.rb
index 102088e9557..38219cacee9 100644
--- a/app/services/projects/enable_deploy_key_service.rb
+++ b/app/services/projects/enable_deploy_key_service.rb
@@ -2,9 +2,10 @@
module Projects
class EnableDeployKeyService < BaseService
- # rubocop: disable CodeReuse/ActiveRecord
def execute
- key = accessible_keys.find_by(id: params[:key_id] || params[:id])
+ key_id = params[:key_id] || params[:id]
+ key = find_accessible_key(key_id)
+
return unless key
unless project.deploy_keys.include?(key)
@@ -13,12 +14,15 @@ module Projects
key
end
- # rubocop: enable CodeReuse/ActiveRecord
private
- def accessible_keys
- current_user.accessible_deploy_keys
+ def find_accessible_key(key_id)
+ if current_user.admin?
+ DeployKey.find_by_id(key_id)
+ else
+ current_user.accessible_deploy_keys.find_by_id(key_id)
+ end
end
end
end
diff --git a/app/services/todos/destroy/entity_leave_service.rb b/app/services/todos/destroy/entity_leave_service.rb
index e8d1bcdd142..ebfb20132d0 100644
--- a/app/services/todos/destroy/entity_leave_service.rb
+++ b/app/services/todos/destroy/entity_leave_service.rb
@@ -45,7 +45,7 @@ module Todos
# rubocop: disable CodeReuse/ActiveRecord
def remove_confidential_issue_todos
Todo.where(
- target_id: confidential_issues.select(:id), target_type: Issue, user_id: user.id
+ target_id: confidential_issues.select(:id), target_type: Issue.name, user_id: user.id
).delete_all
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/todos/destroy/private_features_service.rb b/app/services/todos/destroy/private_features_service.rb
index a8c3fe0ef5a..bd49519d694 100644
--- a/app/services/todos/destroy/private_features_service.rb
+++ b/app/services/todos/destroy/private_features_service.rb
@@ -14,9 +14,9 @@ module Todos
def execute
ProjectFeature.where(project_id: project_ids).each do |project_features|
target_types = []
- target_types << Issue if private?(project_features.issues_access_level)
- target_types << MergeRequest if private?(project_features.merge_requests_access_level)
- target_types << Commit if private?(project_features.repository_access_level)
+ target_types << Issue.name if private?(project_features.issues_access_level)
+ target_types << MergeRequest.name if private?(project_features.merge_requests_access_level)
+ target_types << Commit.name if private?(project_features.repository_access_level)
next if target_types.empty?
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 24ac20fdd29..3f503f3da28 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -28,7 +28,7 @@ module Users
identity_attrs = params.slice(:extern_uid, :provider)
- if identity_attrs.any?
+ unless identity_attrs.empty?
user.identities.build(identity_attrs)
end
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 832ba877558..fdd5c19d562 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -1,6 +1,6 @@
- @hide_top_links = true
- page_title _("Issues")
-- @breadcrumb_link = issues_dashboard_path(assignee_id: current_user.id)
+- @breadcrumb_link = issues_dashboard_path(assignee_username: current_user.username)
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{current_user.name} issues")
@@ -16,7 +16,7 @@
.nav-controls
= render 'shared/issuable/feed_buttons'
-= render 'shared/issuable/filter', type: :issues
+= render 'shared/issuable/search_bar', type: :issues
- if current_user && @no_filters_set
= render 'shared/dashboard/no_filter_selected'
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index fba8d1cf667..77cfa1271df 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -1,6 +1,6 @@
- @hide_top_links = true
- page_title _("Merge Requests")
-- @breadcrumb_link = merge_requests_dashboard_path(assignee_id: current_user.id)
+- @breadcrumb_link = merge_requests_dashboard_path(assignee_username: current_user.username)
.page-title-holder
%h1.page-title= _('Merge Requests')
@@ -12,7 +12,7 @@
.top-area
= render 'shared/issuable/nav', type: :merge_requests, display_count: !@no_filters_set
-= render 'shared/issuable/filter', type: :merge_requests
+= render 'shared/issuable/search_bar', type: :merge_requests
- if current_user && @no_filters_set
= render 'shared/dashboard/no_filter_selected'
diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml
index 5ddb3ece1cb..ec968e435cd 100644
--- a/app/views/devise/shared/_signin_box.html.haml
+++ b/app/views/devise/shared/_signin_box.html.haml
@@ -1,10 +1,10 @@
- if form_based_providers.any?
- if crowd_enabled?
- .login-box.tab-pane.active{ id: "crowd", role: 'tabpanel' }
+ .login-box.tab-pane{ id: "crowd", role: 'tabpanel', class: active_when(form_based_auth_provider_has_active_class?(:crowd)) }
.login-body
= render 'devise/sessions/new_crowd'
- @ldap_servers.each_with_index do |server, i|
- .login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) }
+ .login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && form_based_auth_provider_has_active_class?(:ldapmain)) }
.login-body
= render 'devise/sessions/new_ldap', server: server
- if password_authentication_enabled_for_web?
@@ -12,6 +12,8 @@
.login-body
= render 'devise/sessions/new_base'
+ = render_if_exists 'devise/sessions/new_smartcard'
+
- elsif password_authentication_enabled_for_web?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml
index 7dced0942f5..aee05b6c81c 100644
--- a/app/views/devise/shared/_tabs_ldap.html.haml
+++ b/app/views/devise/shared/_tabs_ldap.html.haml
@@ -1,10 +1,13 @@
%ul.nav-links.new-session-tabs.nav-tabs.nav{ class: ('custom-provider-tabs' if form_based_providers.any?) }
- if crowd_enabled?
%li.nav-item
- = link_to "Crowd", "#crowd", class: 'nav-link active', 'data-toggle' => 'tab'
+ = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab'
- @ldap_servers.each_with_index do |server, i|
%li.nav-item
- = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && !crowd_enabled?)} qa-ldap-tab", 'data-toggle' => 'tab'
+ = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && form_based_auth_provider_has_active_class?(:ldapmain))} qa-ldap-tab", 'data-toggle' => 'tab'
+
+ = render_if_exists 'devise/shared/tab_smartcard'
+
- if password_authentication_enabled_for_web?
%li.nav-item
= link_to 'Standard', '#login-pane', class: 'nav-link qa-standard-tab', 'data-toggle' => 'tab'
diff --git a/app/views/shared/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml
deleted file mode 100644
index 21b37a7c9ae..00000000000
--- a/app/views/shared/_labels_row.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- labels.each do |label|
- %span.label-row.btn-group{ role: "group", aria: { label: label.name }, style: "color: #{text_color_for_bg(label.color)}" }
- = link_to_label(label, subject: @project, css_class: 'btn btn-transparent')
- %button.btn.btn-transparent.label-remove.js-label-filter-remove{ type: "button", style: "background-color: #{label.color};", data: { label: label.title } }
- = icon("times")
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
deleted file mode 100644
index c7037335866..00000000000
--- a/app/views/shared/issuable/_filter.html.haml
+++ /dev/null
@@ -1,32 +0,0 @@
-.issues-filters
- .issues-details-filters.row-content-block.second-block
- = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do
- - if params[:search].present?
- = hidden_field_tag :search, params[:search]
- .issues-other-filters
- .filter-item.inline
- - if params[:author_id].present?
- = hidden_field_tag(:author_id, params[:author_id])
- = dropdown_tag(user_dropdown_label(params[:author_id], "Author"), options: { toggle_class: "js-user-search js-filter-submit js-author-search", title: "Filter by author", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit",
- placeholder: "Search authors", data: { any_user: "Any Author", first_user: current_user&.username, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:author_id], field_name: "author_id", default_label: "Author" } })
-
- .filter-item.inline
- - if params[:assignee_id].present?
- = hidden_field_tag(:assignee_id, params[:assignee_id])
- = dropdown_tag(user_dropdown_label(params[:assignee_id], "Assignee"), options: { toggle_class: "js-user-search js-filter-submit js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit",
- placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: current_user&.username, null_user: true, current_user: true, project_id: @project&.id, group_id: @group&.id, selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
-
- .filter-item.inline.milestone-filter
- = render "shared/issuable/milestone_dropdown", selected: finder.milestones.try(:first), name: :milestone_title, show_any: true, show_upcoming: true, show_started: true
-
- .filter-item.inline.labels-filter
- = render "shared/issuable/label_dropdown", selected: selected_labels, use_id: false, selected_toggle: params[:label_name], data_options: { field_name: "label_name[]" }
-
- - unless @no_filters_set
- .float-right
- = render 'shared/sort_dropdown'
-
- - has_labels = @labels && @labels.any?
- .row-content-block.second-block.filtered-labels{ class: ("hidden" unless has_labels) }
- - if has_labels
- = render 'shared/labels_row', labels: @labels
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 95f32bd0180..824bbe3524b 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -1,7 +1,6 @@
- type = local_assigns.fetch(:type)
- board = local_assigns.fetch(:board, nil)
- block_css_class = type != :boards_modal ? 'row-content-block second-block' : ''
-- full_path = @project.present? ? @project.full_path : @group.full_path
- user_can_admin_list = board && can?(current_user, :admin_list, board.parent)
- show_sorting_dropdown = local_assigns.fetch(:show_sorting_dropdown, true)
@@ -10,7 +9,7 @@
- if type == :boards
#js-multiple-boards-switcher.inline.boards-switcher{ "v-cloak" => true }
= render_if_exists "shared/boards/switcher", board: board
- = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :search]), method: :get, class: 'filter-form js-filter-form' do
+ = form_tag page_filter_path, method: :get, class: 'filter-form js-filter-form' do
- if params[:search].present?
= hidden_field_tag :search, params[:search]
- if @can_bulk_update
@@ -25,7 +24,7 @@
dropdown_class: "filtered-search-history-dropdown",
content_class: "filtered-search-history-dropdown-content",
title: "Recent searches" }) do
- .js-filtered-search-history-dropdown{ data: { full_path: full_path } }
+ .js-filtered-search-history-dropdown{ data: { full_path: search_history_storage_prefix } }
.filtered-search-box-input-container.droplab-dropdown
.scroll-container
%ul.tokens-container.list-unstyled
diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml
index cf525f2bb2d..b5bc1180290 100644
--- a/app/views/users/_overview.html.haml
+++ b/app/views/users/_overview.html.haml
@@ -1,32 +1,30 @@
.row
+ .col-12
+ .calendar-block.prepend-top-default.append-bottom-default
+ .user-calendar.d-none.d-sm-block{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
+ %h4.center.light
+ = spinner nil, true
+ .user-calendar-activities.d-none.d-sm-block
+.row
.col-md-12.col-lg-6
- .calendar-block
- .content-block.hide-bottom-border
- %h4
- = s_('UserProfile|Activity')
- .user-calendar.d-none.d-sm-block.text-left{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- .user-calendar-activities.d-none.d-sm-block
-
- if can?(current_user, :read_cross_project)
.activities-block
- .border-bottom.prepend-top-16
- %h5
- = s_('UserProfile|Recent contributions')
+ .prepend-top-16
+ .d-flex.align-items-center.border-bottom
+ %h4.flex-grow
+ = s_('UserProfile|Activity')
+ = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_path } }
.center.light.loading
- %i.fa.fa-spinner.fa-spin
- .prepend-top-10
- = link_to s_('UserProfile|View all'), user_activity_path, class: "hide js-view-all"
+ = spinner nil, true
.col-md-12.col-lg-6
.projects-block
- .border-bottom.prepend-top-16
- %h4
- = s_('UserProfile|Personal projects')
+ .prepend-top-16
+ .d-flex.align-items-center.border-bottom
+ %h4.flex-grow
+ = s_('UserProfile|Personal projects')
+ = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
.overview-content-list{ data: { href: user_projects_path } }
.center.light.loading
- %i.fa.fa-spinner.fa-spin
- .prepend-top-10
- = link_to s_('UserProfile|View all'), user_projects_path, class: "hide js-view-all"
+ = spinner nil, true
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index d6c8420b744..d11476738e4 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -124,12 +124,6 @@
- if profile_tab?(:activity)
#activity.tab-pane
- .row-content-block.calendar-block.white.second-block.d-none.d-sm-block
- .user-calendar{ data: { calendar_path: user_calendar_path(@user, :json), calendar_activities_path: user_calendar_activities_path, utc_offset: Time.zone.utc_offset } }
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- .user-calendar-activities
-
- if can?(current_user, :read_cross_project)
%h4.prepend-top-20
= s_('UserProfile|Most Recent Activity')