diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-11 00:06:24 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-10-11 00:06:24 +0000 |
commit | 133924c6cc443f5f69e1ab08d43b363d77677cb0 (patch) | |
tree | e893a7d36105fc4acec7038feae5f03bd34cfc2c | |
parent | f607152a0802a68067343ad73f989033cb8e9a06 (diff) | |
download | gitlab-ce-133924c6cc443f5f69e1ab08d43b363d77677cb0.tar.gz |
Add latest changes from gitlab-org/gitlab@master
30 files changed, 228 insertions, 55 deletions
diff --git a/app/assets/images/ci_favicons/favicon_status_preparing.png b/app/assets/images/ci_favicons/favicon_status_preparing.png Binary files differindex f81baa0ece3..f81baa0ece3 100755..100644 --- a/app/assets/images/ci_favicons/favicon_status_preparing.png +++ b/app/assets/images/ci_favicons/favicon_status_preparing.png diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue index 1d53a21c8ac..40d75d53f75 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.vue +++ b/app/assets/javascripts/boards/components/issue_card_inner.vue @@ -99,7 +99,10 @@ export default { return !groupId ? referencePath.split('#')[0] : null; }, orderedLabels() { - return _.sortBy(this.issue.labels, 'title'); + return _.chain(this.issue.labels) + .filter(this.isNonListLabel) + .sortBy('title') + .value(); }, helpLink() { return boardsStore.scopedLabels.helpLink; @@ -130,6 +133,9 @@ export default { if (!label.id) return false; return true; }, + isNonListLabel(label) { + return label.id && !(this.list.type === 'label' && this.list.title === label.title); + }, filterByLabel(label) { if (!this.updateFilters) return; const labelTitle = encodeURIComponent(label.title); @@ -167,7 +173,7 @@ export default { </h4> </div> <div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap"> - <template v-for="label in orderedLabels" v-if="showLabel(label)"> + <template v-for="label in orderedLabels"> <issue-card-inner-scoped-label v-if="showScopedLabel(label)" :key="label.id" diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index 7ead9d46fbb..4be0d05a9b7 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -88,6 +88,14 @@ export function getLocationHash(url = window.location.href) { } /** + * Returns a boolean indicating whether the URL hash contains the given string value + */ +export function doesHashExistInUrl(hashName) { + const hash = getLocationHash(); + return hash && hash.includes(hashName); +} + +/** * Apply the fragment to the given url by returning a new url string that includes * the fragment. If the given url already contains a fragment, the original fragment * will be removed. diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue index 743684e7046..6b1e3298f9a 100644 --- a/app/assets/javascripts/notes/components/discussion_filter.vue +++ b/app/assets/javascripts/notes/components/discussion_filter.vue @@ -1,13 +1,14 @@ <script> import $ from 'jquery'; import { mapGetters, mapActions } from 'vuex'; -import { getLocationHash } from '../../lib/utils/url_utility'; +import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility'; import Icon from '~/vue_shared/components/icon.vue'; import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE, DISCUSSION_TAB_LABEL, DISCUSSION_FILTER_TYPES, + NOTE_UNDERSCORE, } from '../constants'; import notesEventHub from '../event_hub'; @@ -28,7 +29,9 @@ export default { }, data() { return { - currentValue: this.selectedValue, + currentValue: doesHashExistInUrl(NOTE_UNDERSCORE) + ? DISCUSSION_FILTERS_DEFAULT_VALUE + : this.selectedValue, defaultValue: DISCUSSION_FILTERS_DEFAULT_VALUE, displayFilters: true, }; @@ -50,7 +53,6 @@ export default { notesEventHub.$on('dropdownSelect', this.selectFilter); window.addEventListener('hashchange', this.handleLocationHash); - this.handleLocationHash(); }, mounted() { this.toggleCommentsForm(); diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index fd592e965bf..c6c97489e5e 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -1,7 +1,7 @@ <script> import { __ } from '~/locale'; import { mapGetters, mapActions } from 'vuex'; -import { getLocationHash } from '../../lib/utils/url_utility'; +import { getLocationHash, doesHashExistInUrl } from '../../lib/utils/url_utility'; import Flash from '../../flash'; import * as constants from '../constants'; import eventHub from '../event_hub'; @@ -156,19 +156,17 @@ export default { this.isFetching = true; - return this.fetchDiscussions({ path: this.getNotesDataByProp('discussionsPath') }) - .then(() => { - this.initPolling(); - }) + return this.fetchDiscussions(this.getFetchDiscussionsConfig()) + .then(this.initPolling) .then(() => { this.setLoadingState(false); this.setNotesFetchedState(true); eventHub.$emit('fetchedNotesData'); this.isFetching = false; }) - .then(() => this.$nextTick()) - .then(() => this.startTaskList()) - .then(() => this.checkLocationHash()) + .then(this.$nextTick) + .then(this.startTaskList) + .then(this.checkLocationHash) .catch(() => { this.setLoadingState(false); this.setNotesFetchedState(true); @@ -199,9 +197,20 @@ export default { }, startReplying(discussionId) { return this.convertToDiscussion(discussionId) - .then(() => this.$nextTick()) + .then(this.$nextTick) .then(() => eventHub.$emit('startReplying', discussionId)); }, + getFetchDiscussionsConfig() { + const defaultConfig = { path: this.getNotesDataByProp('discussionsPath') }; + + if (doesHashExistInUrl(constants.NOTE_UNDERSCORE)) { + return Object.assign({}, defaultConfig, { + filter: constants.DISCUSSION_FILTERS_DEFAULT_VALUE, + persistFilter: false, + }); + } + return defaultConfig; + }, }, systemNote: constants.SYSTEM_NOTE, }; diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js index bdfb6b8f105..68c117183a1 100644 --- a/app/assets/javascripts/notes/constants.js +++ b/app/assets/javascripts/notes/constants.js @@ -8,8 +8,6 @@ export const OPENED = 'opened'; export const REOPENED = 'reopened'; export const CLOSED = 'closed'; export const MERGED = 'merged'; -export const EMOJI_THUMBSUP = 'thumbsup'; -export const EMOJI_THUMBSDOWN = 'thumbsdown'; export const ISSUE_NOTEABLE_TYPE = 'issue'; export const EPIC_NOTEABLE_TYPE = 'epic'; export const MERGE_REQUEST_NOTEABLE_TYPE = 'MergeRequest'; @@ -19,6 +17,7 @@ export const DESCRIPTION_TYPE = 'changed the description'; export const HISTORY_ONLY_FILTER_VALUE = 2; export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0; export const DISCUSSION_TAB_LABEL = 'show'; +export const NOTE_UNDERSCORE = 'note_'; export const NOTEABLE_TYPE_MAPPING = { Issue: ISSUE_NOTEABLE_TYPE, diff --git a/app/helpers/tags_helper.rb b/app/helpers/tags_helper.rb index de0b92b6fd7..4984b51555d 100644 --- a/app/helpers/tags_helper.rb +++ b/app/helpers/tags_helper.rb @@ -28,4 +28,14 @@ module TagsHelper def protected_tag?(project, tag) ProtectedTag.protected?(project, tag.name) end + + def tag_description_help_text + text = s_('TagsPage|Optionally, add a message to the tag. Leaving this blank creates '\ + 'a %{link_start}lightweight tag.%{link_end}') % { + link_start: '<a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging\" target="_blank" rel="noopener noreferrer">', + link_end: '</a>' + } + + text.html_safe + end end diff --git a/app/models/project_services/slash_commands_service.rb b/app/models/project_services/slash_commands_service.rb index 5bfd06476f0..d436176a52c 100644 --- a/app/models/project_services/slash_commands_service.rb +++ b/app/models/project_services/slash_commands_service.rb @@ -33,9 +33,12 @@ class SlashCommandsService < Service return unless valid_token?(params[:token]) chat_user = find_chat_user(params) + user = chat_user&.user + + if user + unless user.can?(:use_slash_commands) + return Gitlab::SlashCommands::Presenters::Access.new.deactivated if user.deactivated? - if chat_user&.user - unless chat_user.user.can?(:use_slash_commands) return Gitlab::SlashCommands::Presenters::Access.new.access_denied(project) end diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb index 4d66a9e7d67..eca73f0a241 100644 --- a/app/policies/global_policy.rb +++ b/app/policies/global_policy.rb @@ -48,6 +48,7 @@ class GlobalPolicy < BasePolicy prevent :access_git prevent :access_api prevent :receive_notifications + prevent :use_slash_commands end rule { required_terms_not_accepted }.policy do diff --git a/app/views/admin/users/_user_deactivation_effects.html.haml b/app/views/admin/users/_user_deactivation_effects.html.haml index 6cc47214d77..dc3896e18c0 100644 --- a/app/views/admin/users/_user_deactivation_effects.html.haml +++ b/app/views/admin/users/_user_deactivation_effects.html.haml @@ -10,6 +10,8 @@ %li = s_('AdminUsers|The user will not receive any notifications') %li + = s_('AdminUsers|The user will not be able to use slash commands') + %li = s_('AdminUsers|When the user logs back in, their account will reactivate as a fully active account') %li = s_('AdminUsers|Personal projects, group and user history will be left intact') diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 5e6d06d980e..a7f739ab13d 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -31,7 +31,7 @@ .col-sm-10 = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5 .form-text.text-muted - = s_('TagsPage|Optionally, add a message to the tag.') + = tag_description_help_text %hr .form-group.row = label_tag :release_description, s_('TagsPage|Release notes'), class: 'col-form-label col-sm-2' diff --git a/app/workers/prune_old_events_worker.rb b/app/workers/prune_old_events_worker.rb index dc4b7670131..e2d1fb3ed35 100644 --- a/app/workers/prune_old_events_worker.rb +++ b/app/workers/prune_old_events_worker.rb @@ -6,13 +6,13 @@ class PruneOldEventsWorker # rubocop: disable CodeReuse/ActiveRecord def perform - # Contribution calendar shows maximum 12 months of events, we retain 2 years for data integrity. + # Contribution calendar shows maximum 12 months of events, we retain 3 years for data integrity. # Double nested query is used because MySQL doesn't allow DELETE subqueries on the same table. Event.unscoped.where( '(id IN (SELECT id FROM (?) ids_to_remove))', Event.unscoped.where( 'created_at < ?', - (2.years + 1.day).ago) + (3.years + 1.day).ago) .select(:id) .limit(10_000)) .delete_all diff --git a/changelogs/unreleased/10893-hide-redundant-labels-in-issue-boards.yml b/changelogs/unreleased/10893-hide-redundant-labels-in-issue-boards.yml new file mode 100644 index 00000000000..4e5547030de --- /dev/null +++ b/changelogs/unreleased/10893-hide-redundant-labels-in-issue-boards.yml @@ -0,0 +1,5 @@ +--- +title: Hide redundant labels in issue boards +merge_request: 17937 +author: +type: fixed diff --git a/changelogs/unreleased/30497-race-condition-in-discussions-json-request-could-lead-to-notes-show.yml b/changelogs/unreleased/30497-race-condition-in-discussions-json-request-could-lead-to-notes-show.yml new file mode 100644 index 00000000000..32e21a6d003 --- /dev/null +++ b/changelogs/unreleased/30497-race-condition-in-discussions-json-request-could-lead-to-notes-show.yml @@ -0,0 +1,5 @@ +--- +title: Fix notes race condition when linking to specific note +merge_request: 17777 +author: +type: fixed diff --git a/changelogs/unreleased/33750-follow-up-from-resolve-deactivate-a-user-with-self-service-reactiva.yml b/changelogs/unreleased/33750-follow-up-from-resolve-deactivate-a-user-with-self-service-reactiva.yml new file mode 100644 index 00000000000..7fca33c0cd2 --- /dev/null +++ b/changelogs/unreleased/33750-follow-up-from-resolve-deactivate-a-user-with-self-service-reactiva.yml @@ -0,0 +1,5 @@ +--- +title: Do not allow deactivated users to use slash commands +merge_request: 18365 +author: +type: fixed diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 71871d1b1b7..a9f30a5ddd4 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -666,7 +666,7 @@ build: CAUTION: **Warning:** There are some points to be aware of when -[using this feature with new branches or tags *without* pipelines for merge requests](using-onlychanges-without-pipelines-for-merge-requests). +[using this feature with new branches or tags *without* pipelines for merge requests](#using-onlychanges-without-pipelines-for-merge-requests). ##### Using `only:changes` with pipelines for merge requests diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md index fda0936355e..65896bd19cd 100644 --- a/doc/user/profile/account/delete_account.md +++ b/doc/user/profile/account/delete_account.md @@ -55,6 +55,7 @@ A deactivated user: - Cannot access Git repositories or the API. - Will not receive any notifications from GitLab. +- Will not be able to use [slash commands](../../../integration/slash_commands.md). Personal projects, group and user history of the deactivated user will be left intact. diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md index 5721e9858f1..108d4f0b387 100644 --- a/doc/user/profile/account/two_factor_authentication.md +++ b/doc/user/profile/account/two_factor_authentication.md @@ -244,6 +244,12 @@ Sign in and re-enable two-factor authentication as soon as possible. - The user logs out and attempts to log in via `second.host.xyz` - U2F authentication fails, because the U2F key has only been registered on `first.host.xyz`. +## Troubleshooting + +If you are receiving an `invalid pin code` error, this may indicate that there is a time sync issue between the authentication application and the GitLab instance itself. + +Most authentication apps have a feature in the settings for syncing the time for the codes themselves. For Google Authenticator for example, go to `Settings > Time correction for codes`. + <!-- ## Troubleshooting Include any troubleshooting steps that you can foresee. If you know beforehand what issues diff --git a/lib/gitlab/slash_commands/presenters/access.rb b/lib/gitlab/slash_commands/presenters/access.rb index b1bfaa6cb59..9ce1bcfb37c 100644 --- a/lib/gitlab/slash_commands/presenters/access.rb +++ b/lib/gitlab/slash_commands/presenters/access.rb @@ -15,6 +15,15 @@ module Gitlab MESSAGE end + def deactivated + ephemeral_response(text: <<~MESSAGE) + You are not allowed to perform the given chatops command since + your account has been deactivated by your administrator. + + Please log back in from a web browser to reactivate your account at #{Gitlab.config.gitlab.url} + MESSAGE + end + def not_found ephemeral_response(text: "404 not found! GitLab couldn't find what you were looking for! :boom:") end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index c10d94d96ab..94dced318bc 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -375,6 +375,12 @@ msgstr "" msgid "%{title} changes" msgstr "" +msgid "%{total} open issue weight" +msgstr "" + +msgid "%{total} open issues" +msgstr "" + msgid "%{unstaged} unstaged and %{staged} staged changes" msgstr "" @@ -1252,6 +1258,9 @@ msgstr "" msgid "AdminUsers|The user will not be able to access the API" msgstr "" +msgid "AdminUsers|The user will not be able to use slash commands" +msgstr "" + msgid "AdminUsers|The user will not receive any notifications" msgstr "" @@ -2649,7 +2658,7 @@ msgstr "" msgid "Built-in" msgstr "" -msgid "BurndownChartLabel|Guideline" +msgid "Burndown chart" msgstr "" msgid "BurndownChartLabel|Open issue weight" @@ -2658,12 +2667,6 @@ msgstr "" msgid "BurndownChartLabel|Open issues" msgstr "" -msgid "BurndownChartLabel|Progress" -msgstr "" - -msgid "BurndownChartLabel|Remaining" -msgstr "" - msgid "Business" msgstr "" @@ -8303,6 +8306,9 @@ msgstr "" msgid "GroupsTree|Search by name" msgstr "" +msgid "Guideline" +msgstr "" + msgid "HTTP Basic: Access denied\\nYou must use a personal access token with 'api' scope for Git over HTTP.\\nYou can generate one at %{profile_personal_access_tokens_url}" msgstr "" @@ -8943,6 +8949,9 @@ msgstr "" msgid "Issue was closed by %{name} %{reason}" msgstr "" +msgid "Issue weight" +msgstr "" + msgid "IssueBoards|Board" msgstr "" @@ -15814,7 +15823,7 @@ msgstr "" msgid "TagsPage|New tag" msgstr "" -msgid "TagsPage|Optionally, add a message to the tag." +msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}" msgstr "" msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page." @@ -17062,9 +17071,15 @@ msgstr "" msgid "Total artifacts size: %{total_size}" msgstr "" +msgid "Total issues" +msgstr "" + msgid "Total test time for all commits/merges" msgstr "" +msgid "Total weight" +msgstr "" + msgid "Total: %{total}" msgstr "" diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 25aa1c1fb7d..e26582d3444 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -251,7 +251,7 @@ describe 'Issue Boards', :js do expect(page).to have_selector(selector, text: development.title, count: 1) end - it 'issue moves between lists' do + it 'issue moves between lists and does not show the "Development" label since the card is in the "Development" list label' do drag(list_from_index: 1, from_index: 1, list_to_index: 2) wait_for_board_cards(2, 7) @@ -259,10 +259,10 @@ describe 'Issue Boards', :js do wait_for_board_cards(4, 1) expect(find('.board:nth-child(3)')).to have_content(issue6.title) - expect(find('.board:nth-child(3)').all('.board-card').last).to have_content(development.title) + expect(find('.board:nth-child(3)').all('.board-card').last).not_to have_content(development.title) end - it 'issue moves between lists' do + it 'issue moves between lists and does not show the "Planning" label since the card is in the "Planning" list label' do drag(list_from_index: 2, list_to_index: 1) wait_for_board_cards(2, 9) @@ -270,7 +270,7 @@ describe 'Issue Boards', :js do wait_for_board_cards(4, 1) expect(find('.board:nth-child(2)')).to have_content(issue7.title) - expect(find('.board:nth-child(2)').all('.board-card').first).to have_content(planning.title) + expect(find('.board:nth-child(2)').all('.board-card').first).not_to have_content(planning.title) end it 'issue moves from closed' do diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 8497eaf102f..2b923df40c5 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -304,7 +304,8 @@ describe 'Issue Boards', :js do end end - expect(card).to have_selector('.badge', count: 3) + # 'Development' label does not show since the card is in a 'Development' list label + expect(card).to have_selector('.badge', count: 2) expect(card).to have_content(bug.title) end @@ -330,7 +331,8 @@ describe 'Issue Boards', :js do end end - expect(card).to have_selector('.badge', count: 4) + # 'Development' label does not show since the card is in a 'Development' list label + expect(card).to have_selector('.badge', count: 3) expect(card).to have_content(bug.title) expect(card).to have_content(regression.title) end @@ -357,7 +359,8 @@ describe 'Issue Boards', :js do end end - expect(card).to have_selector('.badge', count: 1) + # 'Development' label does not show since the card is in a 'Development' list label + expect(card).to have_selector('.badge', count: 0) expect(card).not_to have_content(stretch.title) end diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js index 41df93c9a48..6edb2e2dce2 100644 --- a/spec/frontend/lib/utils/url_utility_spec.js +++ b/spec/frontend/lib/utils/url_utility_spec.js @@ -136,6 +136,24 @@ describe('URL utility', () => { }); }); + describe('doesHashExistInUrl', () => { + it('should return true when the given string exists in the URL hash', () => { + setWindowLocation({ + href: 'https://gitlab.com/gitlab-org/gitlab-test/issues/1#note_1', + }); + + expect(urlUtils.doesHashExistInUrl('note_')).toBe(true); + }); + + it('should return false when the given string does not exist in the URL hash', () => { + setWindowLocation({ + href: 'https://gitlab.com/gitlab-org/gitlab-test/issues/1#note_1', + }); + + expect(urlUtils.doesHashExistInUrl('doesnotexist')).toBe(false); + }); + }); + describe('setUrlFragment', () => { it('should set fragment when url has no fragment', () => { const url = urlUtils.setUrlFragment('/home/feature', 'usage'); diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index 9e99f961797..314e051665e 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -32,7 +32,10 @@ describe('Issue card component', () => { beforeEach(() => { setFixtures('<div class="test-container"></div>'); - list = listObj; + list = { + ...listObj, + type: 'label', + }; issue = new ListIssue({ title: 'Testing', id: 1, @@ -241,8 +244,8 @@ describe('Issue card component', () => { Vue.nextTick(() => done()); }); - it('renders list label', () => { - expect(component.$el.querySelectorAll('.badge').length).toBe(2); + it('does not render list label but renders all other labels', () => { + expect(component.$el.querySelectorAll('.badge').length).toBe(1); }); it('renders label', () => { @@ -278,7 +281,7 @@ describe('Issue card component', () => { Vue.nextTick() .then(() => { - expect(component.$el.querySelectorAll('.badge').length).toBe(2); + expect(component.$el.querySelectorAll('.badge').length).toBe(1); expect(component.$el.textContent).not.toContain('closed'); done(); diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js index 50ad1442873..41b8f567e08 100644 --- a/spec/javascripts/boards/mock_data.js +++ b/spec/javascripts/boards/mock_data.js @@ -15,7 +15,7 @@ export const listObj = { weight: 3, label: { id: 5000, - title: 'Testing', + title: 'Test', color: 'red', description: 'testing;', textColor: 'white', @@ -30,7 +30,7 @@ export const listObjDuplicate = { weight: 3, label: { id: listObj.label.id, - title: 'Testing', + title: 'Test', color: 'red', description: 'testing;', }, diff --git a/spec/javascripts/notes/components/discussion_filter_spec.js b/spec/javascripts/notes/components/discussion_filter_spec.js index 1c366aee8e2..7524de36ac5 100644 --- a/spec/javascripts/notes/components/discussion_filter_spec.js +++ b/spec/javascripts/notes/components/discussion_filter_spec.js @@ -160,5 +160,28 @@ describe('DiscussionFilter component', () => { done(); }); }); + + it('fetches discussions when there is a hash', done => { + window.location.hash = `note_${discussionMock.notes[0].id}`; + vm.currentValue = discussionFiltersMock[2].value; + spyOn(vm, 'selectFilter'); + vm.handleLocationHash(); + + vm.$nextTick(() => { + expect(vm.selectFilter).toHaveBeenCalled(); + done(); + }); + }); + + it('does not fetch discussions when there is no hash', done => { + window.location.hash = ''; + spyOn(vm, 'selectFilter'); + vm.handleLocationHash(); + + vm.$nextTick(() => { + expect(vm.selectFilter).not.toHaveBeenCalled(); + done(); + }); + }); }); }); diff --git a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb index f00039c634f..c7b83467660 100644 --- a/spec/lib/gitlab/slash_commands/presenters/access_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/access_spec.rb @@ -3,6 +3,13 @@ require 'spec_helper' describe Gitlab::SlashCommands::Presenters::Access do + shared_examples_for 'displays an error message' do + it do + expect(subject[:text]).to match(error_message) + expect(subject[:response_type]).to be(:ephemeral) + end + end + describe '#access_denied' do let(:project) { build(:project) } @@ -10,9 +17,18 @@ describe Gitlab::SlashCommands::Presenters::Access do it { is_expected.to be_a(Hash) } - it 'displays an error message' do - expect(subject[:text]).to match('are not allowed') - expect(subject[:response_type]).to be(:ephemeral) + it_behaves_like 'displays an error message' do + let(:error_message) { 'you do not have access to the GitLab project' } + end + end + + describe '#deactivated' do + subject { described_class.new.deactivated } + + it { is_expected.to be_a(Hash) } + + it_behaves_like 'displays an error message' do + let(:error_message) { 'your account has been deactivated by your administrator' } end end diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb index 48f3d485f4b..880f1bcbc05 100644 --- a/spec/policies/global_policy_spec.rb +++ b/spec/policies/global_policy_spec.rb @@ -288,6 +288,14 @@ describe GlobalPolicy do it { is_expected.not_to be_allowed(:use_slash_commands) } end + context 'when deactivated' do + before do + current_user.deactivate + end + + it { is_expected.not_to be_allowed(:use_slash_commands) } + end + context 'when access locked' do before do current_user.lock_access! diff --git a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb index a99068ab678..370f2072705 100644 --- a/spec/support/shared_examples/chat_slash_commands_shared_examples.rb +++ b/spec/support/shared_examples/chat_slash_commands_shared_examples.rb @@ -94,16 +94,32 @@ RSpec.shared_examples 'chat slash commands service' do subject.trigger(params) end + shared_examples_for 'blocks command execution' do + it do + expect_any_instance_of(Gitlab::SlashCommands::Command).not_to receive(:execute) + + result = subject.trigger(params) + expect(result[:text]).to match(error_message) + end + end + context 'when user is blocked' do before do chat_name.user.block end - it 'blocks command execution' do - expect_any_instance_of(Gitlab::SlashCommands::Command).not_to receive(:execute) + it_behaves_like 'blocks command execution' do + let(:error_message) { 'you do not have access to the GitLab project' } + end + end - result = subject.trigger(params) - expect(result).to include(text: /^You are not allowed/) + context 'when user is deactivated' do + before do + chat_name.user.deactivate + end + + it_behaves_like 'blocks command execution' do + let(:error_message) { 'your account has been deactivated by your administrator' } end end end diff --git a/spec/workers/prune_old_events_worker_spec.rb b/spec/workers/prune_old_events_worker_spec.rb index f1eef1923bf..14235bde070 100644 --- a/spec/workers/prune_old_events_worker_spec.rb +++ b/spec/workers/prune_old_events_worker_spec.rb @@ -6,12 +6,12 @@ describe PruneOldEventsWorker do describe '#perform' do let(:user) { create(:user) } - let!(:expired_event) { create(:event, :closed, author: user, created_at: 25.months.ago) } + let!(:expired_event) { create(:event, :closed, author: user, created_at: 37.months.ago) } let!(:not_expired_1_day_event) { create(:event, :closed, author: user, created_at: 1.day.ago) } let!(:not_expired_13_month_event) { create(:event, :closed, author: user, created_at: 13.months.ago) } - let!(:not_expired_2_years_event) { create(:event, :closed, author: user, created_at: 2.years.ago) } + let!(:not_expired_3_years_event) { create(:event, :closed, author: user, created_at: 3.years.ago) } - it 'prunes events older than 2 years' do + it 'prunes events older than 3 years' do expect { subject.perform }.to change { Event.count }.by(-1) expect(Event.find_by(id: expired_event.id)).to be_nil end @@ -26,9 +26,9 @@ describe PruneOldEventsWorker do expect(not_expired_13_month_event.reload).to be_present end - it 'leaves events from 2 years ago' do + it 'leaves events from 3 years ago' do subject.perform - expect(not_expired_2_years_event).to be_present + expect(not_expired_3_years_event).to be_present end end end |