Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
9a34a91714
commit
26c50e0eb9
29 changed files with 381 additions and 151 deletions
|
@ -48,6 +48,7 @@ export default {
|
|||
<div>
|
||||
<gl-table
|
||||
class="members-table"
|
||||
data-testid="members-table"
|
||||
head-variant="white"
|
||||
stacked="lg"
|
||||
:fields="filteredFields"
|
||||
|
|
|
@ -8,7 +8,6 @@ class ApplicationSetting < ApplicationRecord
|
|||
include IgnorableColumns
|
||||
|
||||
ignore_column :namespace_storage_size_limit, remove_with: '13.5', remove_after: '2020-09-22'
|
||||
ignore_column :instance_statistics_visibility_private, remove_with: '13.6', remove_after: '2020-10-22'
|
||||
|
||||
INSTANCE_REVIEW_MIN_USERS = 50
|
||||
GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
|
||||
|
|
|
@ -14,6 +14,8 @@ class AlertsService < Service
|
|||
before_validation :prevent_token_assignment
|
||||
before_validation :ensure_token, if: :activated?
|
||||
|
||||
after_save :update_http_integration
|
||||
|
||||
def url
|
||||
return if instance? || template?
|
||||
|
||||
|
@ -77,6 +79,14 @@ class AlertsService < Service
|
|||
def url_helpers
|
||||
Gitlab::Routing.url_helpers
|
||||
end
|
||||
|
||||
def update_http_integration
|
||||
return unless project_id && type == 'AlertsService'
|
||||
|
||||
AlertManagement::SyncAlertServiceDataService # rubocop: disable CodeReuse/ServiceClass
|
||||
.new(self)
|
||||
.execute
|
||||
end
|
||||
end
|
||||
|
||||
AlertsService.prepend_if_ee('EE::AlertsService')
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AlertManagement
|
||||
class SyncAlertServiceDataService
|
||||
# @param alert_service [AlertsService]
|
||||
def initialize(alert_service)
|
||||
@alert_service = alert_service
|
||||
end
|
||||
|
||||
def execute
|
||||
http_integration = find_http_integration
|
||||
|
||||
result = if http_integration
|
||||
update_integration_data(http_integration)
|
||||
else
|
||||
create_integration
|
||||
end
|
||||
|
||||
result ? ServiceResponse.success : ServiceResponse.error(message: 'Update failed')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :alert_service
|
||||
|
||||
def find_http_integration
|
||||
AlertManagement::HttpIntegrationsFinder.new(
|
||||
alert_service.project,
|
||||
endpoint_identifier: ::AlertManagement::HttpIntegration::LEGACY_IDENTIFIER
|
||||
)
|
||||
.execute
|
||||
.first
|
||||
end
|
||||
|
||||
def create_integration
|
||||
new_integration = AlertManagement::HttpIntegration.create(
|
||||
project_id: alert_service.project_id,
|
||||
name: 'HTTP endpoint',
|
||||
endpoint_identifier: AlertManagement::HttpIntegration::LEGACY_IDENTIFIER,
|
||||
active: alert_service.active,
|
||||
encrypted_token: alert_service.data.encrypted_token,
|
||||
encrypted_token_iv: alert_service.data.encrypted_token_iv
|
||||
)
|
||||
|
||||
new_integration.persisted?
|
||||
end
|
||||
|
||||
def update_integration_data(http_integration)
|
||||
http_integration.update(
|
||||
active: alert_service.active,
|
||||
encrypted_token: alert_service.data.encrypted_token,
|
||||
encrypted_token_iv: alert_service.data.encrypted_token_iv
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,7 +16,7 @@
|
|||
= sprite_icon('search', css_class: 'gl-vertical-align-middle!')
|
||||
= label_tag :sort_by, _('Sort by'), class: 'col-form-label label-bold px-2'
|
||||
= render 'shared/members/sort_dropdown'
|
||||
%ul.content-list.members-list{ data: { qa_selector: 'members_list' } }
|
||||
%ul.content-list.members-list{ data: { qa_selector: 'members_list', testid: 'members-table' } }
|
||||
= render partial: 'shared/members/member',
|
||||
collection: members, as: :member,
|
||||
locals: { membership_source: project,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- filter = params[:two_factor] || 'everyone'
|
||||
- filter_options = { 'everyone' => _('Everyone'), 'enabled' => _('Enabled'), 'disabled' => _('Disabled') }
|
||||
.dropdown.inline.member-filter-2fa-dropdown
|
||||
= dropdown_toggle(filter_options[filter], { toggle: 'dropdown' })
|
||||
.dropdown.inline.member-filter-2fa-dropdown{ data: { testid: 'member-filter-2fa-dropdown' } }
|
||||
= dropdown_toggle(filter_options[filter], { toggle: 'dropdown', testid: 'dropdown-toggle' })
|
||||
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
|
||||
%li.dropdown-header
|
||||
= _("Filter by two-factor authentication")
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
- import_path = local_assigns[:import_path]
|
||||
.row
|
||||
.col-sm-12
|
||||
= form_tag submit_url, class: 'invite-users-form', method: :post do
|
||||
= form_tag submit_url, class: 'invite-users-form', data: { testid: 'invite-users-form' }, method: :post do
|
||||
.form-group
|
||||
= label_tag :user_ids, _("GitLab member or Email address"), class: "label-bold"
|
||||
= users_select_tag(:user_ids, multiple: true, class: 'input-clamp qa-member-select-field', scope: :all, email_user: true, placeholder: 'Search for members to update or invite')
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
|
||||
.search-control-wrap.gl-relative
|
||||
= search_field_tag name, params[name], { placeholder: _('Search'), class: 'form-control', spellcheck: false }
|
||||
%button.user-search-btn.border-left.gl-display-flex.gl-align-items-center.gl-justify-content-center{ type: 'submit', 'aria': { label: _('Submit search') } }
|
||||
%button.user-search-btn.border-left.gl-display-flex.gl-align-items-center.gl-justify-content-center{ type: 'submit', 'aria': { label: _('Submit search') }, data: { testid: 'user-search-submit' } }
|
||||
= sprite_icon('search')
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.dropdown.inline.qa-user-sort-dropdown
|
||||
= dropdown_toggle(member_sort_options_hash[@sort], { toggle: 'dropdown' })
|
||||
.dropdown.inline.qa-user-sort-dropdown{ data: { testid: 'user-sort-dropdown' } }
|
||||
= dropdown_toggle(member_sort_options_hash[@sort], { toggle: 'dropdown', testid: 'dropdown-toggle' })
|
||||
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable
|
||||
%li.dropdown-header
|
||||
= _("Sort by")
|
||||
|
@ -8,12 +8,12 @@
|
|||
= link_to filter_group_project_member_path(sort: value), class: ("is-active" if @sort == value) do
|
||||
= title
|
||||
%li.divider
|
||||
%li{ data: { 'qa-selector': 'filter-members-with-inherited-permissions' } }
|
||||
%li{ data: { testid: 'filter-members-with-inherited-permissions' } }
|
||||
= link_to filter_group_project_member_path(with_inherited_permissions: nil), class: ("is-active" unless params[:with_inherited_permissions].present?) do
|
||||
= _("Show all members")
|
||||
%li{ data: { 'qa-selector': 'filter-members-with-inherited-permissions' } }
|
||||
%li{ data: { testid: 'filter-members-with-inherited-permissions' } }
|
||||
= link_to filter_group_project_member_path(with_inherited_permissions: 'exclude'), class: ("is-active" if params[:with_inherited_permissions] == 'exclude') do
|
||||
= _("Show only direct members")
|
||||
%li{ data: { 'qa-selector': 'filter-members-with-inherited-permissions' } }
|
||||
%li{ data: { testid: 'filter-members-with-inherited-permissions' } }
|
||||
= link_to filter_group_project_member_path(with_inherited_permissions: 'only'), class: ("is-active" if params[:with_inherited_permissions] == 'only') do
|
||||
= _("Show only inherited members")
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate Alert Service to HTTP Integrations model
|
||||
merge_request: 46188
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateServicesToHttpIntegrations < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
ALERT_SERVICE_TYPE = 'AlertsService'
|
||||
SERVICE_NAMES_IDENTIFIER = {
|
||||
name: 'HTTP endpoint',
|
||||
identifier: 'legacy'
|
||||
}
|
||||
|
||||
class HttpIntegration < ActiveRecord::Base
|
||||
self.table_name = 'alert_management_http_integrations'
|
||||
end
|
||||
|
||||
# For each Alerts service,
|
||||
# Create the matching HttpIntegration
|
||||
def up
|
||||
HttpIntegration.reset_column_information
|
||||
|
||||
sql = <<~SQL
|
||||
SELECT * FROM services
|
||||
JOIN alerts_service_data
|
||||
ON (services.id = alerts_service_data.service_id)
|
||||
WHERE type = '#{ALERT_SERVICE_TYPE}'
|
||||
AND active = TRUE
|
||||
SQL
|
||||
|
||||
current_time = Time.current
|
||||
|
||||
values = select_all(sql).map do |alerts_service|
|
||||
{
|
||||
project_id: alerts_service['project_id'],
|
||||
name: SERVICE_NAMES_IDENTIFIER[:name],
|
||||
endpoint_identifier: SERVICE_NAMES_IDENTIFIER[:identifier],
|
||||
encrypted_token: alerts_service['encrypted_token'],
|
||||
encrypted_token_iv: alerts_service['encrypted_token_iv'],
|
||||
active: alerts_service['active'],
|
||||
updated_at: current_time,
|
||||
created_at: current_time
|
||||
}
|
||||
end
|
||||
|
||||
HttpIntegration.insert_all(values) if values.present?
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
1
db/schema_migrations/20201027002551
Normal file
1
db/schema_migrations/20201027002551
Normal file
|
@ -0,0 +1 @@
|
|||
34e357b739235d627e543e1bc7202e0cf26f5b1ca8021bb25357e29e883f785b
|
|
@ -19,7 +19,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
it 'closes an issue', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/225303', type: :bug }, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/852' do
|
||||
it 'closes an issue', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/225303', type: :bug }, testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1085' do
|
||||
closed_issue.visit!
|
||||
|
||||
Page::Project::Issue::Show.perform do |issue_page|
|
||||
|
|
8
spec/factories/alerts_service_data.rb
Normal file
8
spec/factories/alerts_service_data.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :alerts_service_data do
|
||||
service { association(:alerts_service) }
|
||||
token { SecureRandom.hex }
|
||||
end
|
||||
end
|
|
@ -56,6 +56,10 @@ FactoryBot.define do
|
|||
trait :inactive do
|
||||
active { false }
|
||||
end
|
||||
|
||||
before(:create) do |service|
|
||||
service.data = build(:alerts_service_data, service: service)
|
||||
end
|
||||
end
|
||||
|
||||
factory :drone_ci_service do
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'Admin Groups' do
|
||||
include Select2Helper
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
|
||||
let(:user) { create :user }
|
||||
|
@ -11,8 +12,6 @@ RSpec.describe 'Admin Groups' do
|
|||
let!(:current_user) { create(:admin) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
sign_in(current_user)
|
||||
stub_application_setting(default_group_visibility: internal)
|
||||
end
|
||||
|
@ -176,7 +175,7 @@ RSpec.describe 'Admin Groups' do
|
|||
|
||||
click_button 'Invite'
|
||||
|
||||
page.within '[data-qa-selector="members_list"]' do
|
||||
page.within members_table do
|
||||
expect(page).to have_content(current_user.name)
|
||||
expect(page).to have_content('Developer')
|
||||
end
|
||||
|
|
|
@ -2,16 +2,19 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Groups > Members > Filter members' do
|
||||
RSpec.describe 'Groups > Members > Filter members', :js do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:nested_group_user) { create(:user) }
|
||||
let(:user_with_2fa) { create(:user, :two_factor_via_otp) }
|
||||
let(:group) { create(:group) }
|
||||
let(:nested_group) { create(:group, parent: group) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
two_factor_auth_dropdown_toggle_selector = '[data-testid="member-filter-2fa-dropdown"] [data-testid="dropdown-toggle"]'
|
||||
active_inherited_members_filter_selector = '[data-testid="filter-members-with-inherited-permissions"] a.is-active'
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
group.add_maintainer(user_with_2fa)
|
||||
nested_group.add_maintainer(nested_group_user)
|
||||
|
@ -24,23 +27,23 @@ RSpec.describe 'Groups > Members > Filter members' do
|
|||
|
||||
expect(member(0)).to include(user.name)
|
||||
expect(member(1)).to include(user_with_2fa.name)
|
||||
expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Everyone')
|
||||
expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Everyone')
|
||||
end
|
||||
|
||||
it 'shows only 2FA members' do
|
||||
visit_members_list(group, two_factor: 'enabled')
|
||||
|
||||
expect(member(0)).to include(user_with_2fa.name)
|
||||
expect(members_list.size).to eq(1)
|
||||
expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Enabled')
|
||||
expect(all_rows.size).to eq(1)
|
||||
expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Enabled')
|
||||
end
|
||||
|
||||
it 'shows only non 2FA members' do
|
||||
visit_members_list(group, two_factor: 'disabled')
|
||||
|
||||
expect(member(0)).to include(user.name)
|
||||
expect(members_list.size).to eq(1)
|
||||
expect(page).to have_css('.member-filter-2fa-dropdown .dropdown-toggle-text', text: 'Disabled')
|
||||
expect(all_rows.size).to eq(1)
|
||||
expect(page).to have_css(two_factor_auth_dropdown_toggle_selector, text: 'Disabled')
|
||||
end
|
||||
|
||||
it 'shows inherited members by default' do
|
||||
|
@ -49,35 +52,31 @@ RSpec.describe 'Groups > Members > Filter members' do
|
|||
expect(member(0)).to include(user.name)
|
||||
expect(member(1)).to include(user_with_2fa.name)
|
||||
expect(member(2)).to include(nested_group_user.name)
|
||||
expect(members_list.size).to eq(3)
|
||||
expect(all_rows.size).to eq(3)
|
||||
|
||||
expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show all members')
|
||||
expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show all members', visible: false)
|
||||
end
|
||||
|
||||
it 'shows only group members' do
|
||||
visit_members_list(nested_group, with_inherited_permissions: 'exclude')
|
||||
expect(member(0)).to include(nested_group_user.name)
|
||||
expect(members_list.size).to eq(1)
|
||||
expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show only direct members')
|
||||
expect(all_rows.size).to eq(1)
|
||||
expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only direct members', visible: false)
|
||||
end
|
||||
|
||||
it 'shows only inherited members' do
|
||||
visit_members_list(nested_group, with_inherited_permissions: 'only')
|
||||
expect(member(0)).to include(user.name)
|
||||
expect(member(1)).to include(user_with_2fa.name)
|
||||
expect(members_list.size).to eq(2)
|
||||
expect(page).to have_css('[data-qa-selector="filter-members-with-inherited-permissions"] a.is-active', text: 'Show only inherited members')
|
||||
expect(all_rows.size).to eq(2)
|
||||
expect(page).to have_css(active_inherited_members_filter_selector, text: 'Show only inherited members', visible: false)
|
||||
end
|
||||
|
||||
def visit_members_list(group, options = {})
|
||||
visit group_group_members_path(group.to_param, options)
|
||||
end
|
||||
|
||||
def members_list
|
||||
page.all('ul.content-list > li')
|
||||
end
|
||||
|
||||
def member(number)
|
||||
members_list[number].text
|
||||
all_rows[number].text
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Groups > Members > Leave group' do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:other_user) { create(:user) }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
gitlab_sign_in(user)
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
it 'guest leaves the group' do
|
||||
|
@ -61,7 +61,7 @@ RSpec.describe 'Groups > Members > Leave group' do
|
|||
expect(group.users).not_to include(user)
|
||||
end
|
||||
|
||||
it 'owner can not leave the group if they are the last owner' do
|
||||
it 'owner can not leave the group if they are the last owner', :js do
|
||||
group.add_owner(user)
|
||||
|
||||
visit group_path(group)
|
||||
|
@ -70,7 +70,7 @@ RSpec.describe 'Groups > Members > Leave group' do
|
|||
|
||||
visit group_group_members_path(group)
|
||||
|
||||
expect(find(:css, '.project-members-page li', text: user.name)).to have_no_selector(:css, 'a.btn-danger')
|
||||
expect(members_table).not_to have_selector 'button[title="Leave"]'
|
||||
end
|
||||
|
||||
it 'owner can not leave the group by url param if they are the last owner', :js do
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Groups > Members > List members' do
|
||||
include Select2Helper
|
||||
include Spec::Support::Helpers::Features::ListRowsHelpers
|
||||
RSpec.describe 'Groups > Members > List members', :js do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user1) { create(:user, name: 'John Doe') }
|
||||
let(:user2) { create(:user, name: 'Mary Jane') }
|
||||
|
@ -12,8 +11,6 @@ RSpec.describe 'Groups > Members > List members' do
|
|||
let(:nested_group) { create(:group, parent: group) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
sign_in(user1)
|
||||
end
|
||||
|
||||
|
@ -42,10 +39,12 @@ RSpec.describe 'Groups > Members > List members' do
|
|||
group.add_developer(user2)
|
||||
end
|
||||
|
||||
subject { visit group_group_members_path(group) }
|
||||
it 'shows the status' do
|
||||
create(:user_status, user: user2, emoji: 'smirk', message: 'Authoring this object')
|
||||
|
||||
it_behaves_like 'showing user status' do
|
||||
let(:user_with_status) { user2 }
|
||||
visit group_group_members_path(nested_group)
|
||||
|
||||
expect(first_row).to have_selector('gl-emoji[data-name="smirk"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,13 +4,11 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'Groups > Members > Manage groups', :js do
|
||||
include Select2Helper
|
||||
include Spec::Support::Helpers::Features::ListRowsHelpers
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
@ -51,7 +49,6 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
|
|||
end
|
||||
|
||||
before do
|
||||
travel_to Time.now.utc.beginning_of_day
|
||||
group_link.update!(additional_link_attrs)
|
||||
|
||||
shared_group.add_owner(user)
|
||||
|
@ -63,8 +60,12 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
|
|||
|
||||
expect(page).to have_content(shared_with_group.name)
|
||||
|
||||
accept_confirm do
|
||||
find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-danger').click
|
||||
page.within(first_row) do
|
||||
click_button 'Remove group'
|
||||
end
|
||||
|
||||
page.within('[role="dialog"]') do
|
||||
click_button('Remove group')
|
||||
end
|
||||
|
||||
expect(page).not_to have_content(shared_with_group.name)
|
||||
|
@ -75,7 +76,7 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
|
|||
|
||||
page.within(first_row) do
|
||||
click_button('Developer')
|
||||
click_link('Maintainer')
|
||||
click_button('Maintainer')
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
@ -86,33 +87,30 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
|
|||
it 'updates expiry date' do
|
||||
click_groups_tab
|
||||
|
||||
expires_at_field = "member_expires_at_#{shared_with_group.id}"
|
||||
fill_in "member_expires_at_#{shared_with_group.id}", with: 3.days.from_now.to_date
|
||||
page.within first_row do
|
||||
fill_in 'Expiration date', with: 5.days.from_now.to_date
|
||||
find_field('Expiration date').native.send_keys :enter
|
||||
|
||||
find_field(expires_at_field).native.send_keys :enter
|
||||
wait_for_requests
|
||||
wait_for_requests
|
||||
|
||||
page.within(find('li.group_member')) do
|
||||
expect(page).to have_content('Expires in 3 days')
|
||||
expect(page).to have_content(/in \d days/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when expiry date is set' do
|
||||
let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } }
|
||||
let(:additional_link_attrs) { { expires_at: 5.days.from_now.to_date } }
|
||||
|
||||
it 'clears expiry date' do
|
||||
click_groups_tab
|
||||
|
||||
page.within(find('li.group_member')) do
|
||||
expect(page).to have_content('Expires in 3 days')
|
||||
page.within first_row do
|
||||
expect(page).to have_content(/in \d days/)
|
||||
|
||||
page.within(find('.js-edit-member-form')) do
|
||||
find('.js-clear-input').click
|
||||
end
|
||||
find('[data-testid="clear-button"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_content('Expires in')
|
||||
expect(page).to have_content('No expiration set')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -128,6 +126,7 @@ RSpec.describe 'Groups > Members > Manage groups', :js do
|
|||
end
|
||||
|
||||
def click_groups_tab
|
||||
expect(page).to have_link 'Groups'
|
||||
click_link "Groups"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,15 +4,13 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'Groups > Members > Manage members' do
|
||||
include Select2Helper
|
||||
include Spec::Support::Helpers::Features::ListRowsHelpers
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user1) { create(:user, name: 'John Doe') }
|
||||
let(:user2) { create(:user, name: 'Mary Jane') }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
sign_in(user1)
|
||||
end
|
||||
|
||||
|
@ -24,7 +22,7 @@ RSpec.describe 'Groups > Members > Manage members' do
|
|||
|
||||
page.within(second_row) do
|
||||
click_button('Developer')
|
||||
click_link('Owner')
|
||||
click_button('Owner')
|
||||
|
||||
expect(page).to have_button('Owner')
|
||||
end
|
||||
|
@ -71,11 +69,14 @@ RSpec.describe 'Groups > Members > Manage members' do
|
|||
visit group_group_members_path(group)
|
||||
|
||||
# Open modal
|
||||
find(:css, '.project-members-page li', text: user2.name).find(:css, 'button.btn-danger').click
|
||||
page.within(second_row) do
|
||||
click_button 'Remove member'
|
||||
end
|
||||
|
||||
expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
|
||||
|
||||
click_on('Remove member')
|
||||
page.within('[role="dialog"]') do
|
||||
expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests'
|
||||
click_button('Remove member')
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
||||
|
@ -103,16 +104,17 @@ RSpec.describe 'Groups > Members > Manage members' do
|
|||
|
||||
add_user('test@example.com', 'Reporter')
|
||||
|
||||
click_link('Invited')
|
||||
expect(page).to have_link 'Invited'
|
||||
click_link 'Invited'
|
||||
|
||||
page.within('.content-list.members-list') do
|
||||
page.within(members_table) do
|
||||
expect(page).to have_content('test@example.com')
|
||||
expect(page).to have_content('Invited')
|
||||
expect(page).to have_button('Reporter')
|
||||
end
|
||||
end
|
||||
|
||||
it 'guest can not manage other users' do
|
||||
it 'guest can not manage other users', :js do
|
||||
group.add_guest(user1)
|
||||
group.add_developer(user2)
|
||||
|
||||
|
@ -126,7 +128,7 @@ RSpec.describe 'Groups > Members > Manage members' do
|
|||
expect(page).not_to have_button 'Developer'
|
||||
|
||||
# Can not remove user2
|
||||
expect(page).not_to have_css('a.btn-danger')
|
||||
expect(page).not_to have_selector 'button[title="Remove member"]'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,17 +4,13 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js do
|
||||
include Select2Helper
|
||||
include ActiveSupport::Testing::TimeHelpers
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let_it_be(:user1) { create(:user, name: 'John Doe') }
|
||||
let_it_be(:group) { create(:group) }
|
||||
let(:new_member) { create(:user, name: 'Mary Jane') }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
travel_to Time.now.utc.beginning_of_day
|
||||
|
||||
group.add_owner(user1)
|
||||
sign_in(user1)
|
||||
end
|
||||
|
@ -22,17 +18,17 @@ RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js
|
|||
it 'expiration date is displayed in the members list' do
|
||||
visit group_group_members_path(group)
|
||||
|
||||
page.within '.invite-users-form' do
|
||||
page.within invite_users_form do
|
||||
select2(new_member.id, from: '#user_ids', multiple: true)
|
||||
|
||||
fill_in 'expires_at', with: 3.days.from_now.to_date
|
||||
fill_in 'expires_at', with: 5.days.from_now.to_date
|
||||
find_field('expires_at').native.send_keys :enter
|
||||
|
||||
click_on 'Invite'
|
||||
end
|
||||
|
||||
page.within "#group_member_#{group_member_id}" do
|
||||
expect(page).to have_content('Expires in 3 days')
|
||||
page.within second_row do
|
||||
expect(page).to have_content(/in \d days/)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -40,32 +36,28 @@ RSpec.describe 'Groups > Members > Owner adds member with expiration date', :js
|
|||
group.add_developer(new_member)
|
||||
visit group_group_members_path(group)
|
||||
|
||||
page.within "#group_member_#{group_member_id}" do
|
||||
fill_in 'Expiration date', with: 3.days.from_now.to_date
|
||||
page.within second_row do
|
||||
fill_in 'Expiration date', with: 5.days.from_now.to_date
|
||||
find_field('Expiration date').native.send_keys :enter
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).to have_content('Expires in 3 days')
|
||||
expect(page).to have_content(/in \d days/)
|
||||
end
|
||||
end
|
||||
|
||||
it 'clears expiration date' do
|
||||
create(:group_member, :developer, user: new_member, group: group, expires_at: 3.days.from_now.to_date)
|
||||
create(:group_member, :developer, user: new_member, group: group, expires_at: 5.days.from_now.to_date)
|
||||
visit group_group_members_path(group)
|
||||
|
||||
page.within "#group_member_#{group_member_id}" do
|
||||
expect(page).to have_content('Expires in 3 days')
|
||||
page.within second_row do
|
||||
expect(page).to have_content(/in \d days/)
|
||||
|
||||
find('.js-clear-input').click
|
||||
find('[data-testid="clear-button"]').click
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_content('Expires in')
|
||||
expect(page).to have_content('No expiration set')
|
||||
end
|
||||
end
|
||||
|
||||
def group_member_id
|
||||
group.members.find_by(user_id: new_member).id
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Groups > Members > Maintainer manages access requests' do
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'Maintainer manages access requests' do
|
||||
let(:has_tabs) { true }
|
||||
let(:entity) { create(:group, :public) }
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Search group member' do
|
||||
RSpec.describe 'Search group member', :js do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user) { create :user }
|
||||
let(:member) { create :user }
|
||||
|
||||
|
@ -14,8 +16,6 @@ RSpec.describe 'Search group member' do
|
|||
end
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
|
||||
sign_in(user)
|
||||
visit group_group_members_path(guest_group)
|
||||
end
|
||||
|
@ -23,11 +23,10 @@ RSpec.describe 'Search group member' do
|
|||
it 'renders member users' do
|
||||
page.within '[data-testid="user-search-form"]' do
|
||||
fill_in 'search', with: member.name
|
||||
find('.user-search-btn').click
|
||||
find('[data-testid="user-search-submit"]').click
|
||||
end
|
||||
|
||||
group_members_list = find('[data-qa-selector="members_list"]')
|
||||
expect(group_members_list).to have_content(member.name)
|
||||
expect(group_members_list).not_to have_content(user.name)
|
||||
expect(members_table).to have_content(member.name)
|
||||
expect(members_table).not_to have_content(user.name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Groups > Members > Sort members' do
|
||||
RSpec.describe 'Groups > Members > Sort members', :js do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:owner) { create(:user, name: 'John Doe') }
|
||||
let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) }
|
||||
let(:group) { create(:group) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vue_group_members_list: false)
|
||||
dropdown_toggle_selector = '[data-testid="user-sort-dropdown"] [data-testid="dropdown-toggle"]'
|
||||
|
||||
before do
|
||||
create(:group_member, :owner, user: owner, group: group, created_at: 5.days.ago)
|
||||
create(:group_member, :developer, user: developer, group: group, created_at: 3.days.ago)
|
||||
|
||||
|
@ -19,84 +21,76 @@ RSpec.describe 'Groups > Members > Sort members' do
|
|||
it 'sorts alphabetically by default' do
|
||||
visit_members_list(sort: nil)
|
||||
|
||||
expect(first_member).to include(owner.name)
|
||||
expect(second_member).to include(developer.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
|
||||
expect(first_row.text).to include(owner.name)
|
||||
expect(second_row.text).to include(developer.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
|
||||
end
|
||||
|
||||
it 'sorts by access level ascending' do
|
||||
visit_members_list(sort: :access_level_asc)
|
||||
|
||||
expect(first_member).to include(developer.name)
|
||||
expect(second_member).to include(owner.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, ascending')
|
||||
expect(first_row.text).to include(developer.name)
|
||||
expect(second_row.text).to include(owner.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, ascending')
|
||||
end
|
||||
|
||||
it 'sorts by access level descending' do
|
||||
visit_members_list(sort: :access_level_desc)
|
||||
|
||||
expect(first_member).to include(owner.name)
|
||||
expect(second_member).to include(developer.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Access level, descending')
|
||||
expect(first_row.text).to include(owner.name)
|
||||
expect(second_row.text).to include(developer.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Access level, descending')
|
||||
end
|
||||
|
||||
it 'sorts by last joined' do
|
||||
visit_members_list(sort: :last_joined)
|
||||
|
||||
expect(first_member).to include(developer.name)
|
||||
expect(second_member).to include(owner.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Last joined')
|
||||
expect(first_row.text).to include(developer.name)
|
||||
expect(second_row.text).to include(owner.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Last joined')
|
||||
end
|
||||
|
||||
it 'sorts by oldest joined' do
|
||||
visit_members_list(sort: :oldest_joined)
|
||||
|
||||
expect(first_member).to include(owner.name)
|
||||
expect(second_member).to include(developer.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest joined')
|
||||
expect(first_row.text).to include(owner.name)
|
||||
expect(second_row.text).to include(developer.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest joined')
|
||||
end
|
||||
|
||||
it 'sorts by name ascending' do
|
||||
visit_members_list(sort: :name_asc)
|
||||
|
||||
expect(first_member).to include(owner.name)
|
||||
expect(second_member).to include(developer.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, ascending')
|
||||
expect(first_row.text).to include(owner.name)
|
||||
expect(second_row.text).to include(developer.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Name, ascending')
|
||||
end
|
||||
|
||||
it 'sorts by name descending' do
|
||||
visit_members_list(sort: :name_desc)
|
||||
|
||||
expect(first_member).to include(developer.name)
|
||||
expect(second_member).to include(owner.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Name, descending')
|
||||
expect(first_row.text).to include(developer.name)
|
||||
expect(second_row.text).to include(owner.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Name, descending')
|
||||
end
|
||||
|
||||
it 'sorts by recent sign in', :clean_gitlab_redis_shared_state do
|
||||
visit_members_list(sort: :recent_sign_in)
|
||||
|
||||
expect(first_member).to include(owner.name)
|
||||
expect(second_member).to include(developer.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Recent sign in')
|
||||
expect(first_row.text).to include(owner.name)
|
||||
expect(second_row.text).to include(developer.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Recent sign in')
|
||||
end
|
||||
|
||||
it 'sorts by oldest sign in', :clean_gitlab_redis_shared_state do
|
||||
visit_members_list(sort: :oldest_sign_in)
|
||||
|
||||
expect(first_member).to include(developer.name)
|
||||
expect(second_member).to include(owner.name)
|
||||
expect(page).to have_css('.qa-user-sort-dropdown .dropdown-toggle-text', text: 'Oldest sign in')
|
||||
expect(first_row.text).to include(developer.name)
|
||||
expect(second_row.text).to include(owner.name)
|
||||
expect(page).to have_css(dropdown_toggle_selector, text: 'Oldest sign in')
|
||||
end
|
||||
|
||||
def visit_members_list(sort:)
|
||||
visit group_group_members_path(group.to_param, sort: sort)
|
||||
end
|
||||
|
||||
def first_member
|
||||
page.all('ul.content-list > li').first.text
|
||||
end
|
||||
|
||||
def second_member
|
||||
page.all('ul.content-list > li').last.text
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require Rails.root.join('db', 'migrate', '20201027002551_migrate_services_to_http_integrations.rb')
|
||||
|
||||
RSpec.describe MigrateServicesToHttpIntegrations do
|
||||
let!(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') }
|
||||
let!(:project) { table(:projects).create!(id: 1, namespace_id: namespace.id) }
|
||||
let!(:alert_service) { table(:services).create!(type: 'AlertsService', project_id: project.id, active: true) }
|
||||
let!(:alert_service_data) { table(:alerts_service_data).create!(service_id: alert_service.id, encrypted_token: 'test', encrypted_token_iv: 'test')}
|
||||
let(:http_integrations) { table(:alert_management_http_integrations) }
|
||||
|
||||
describe '#up' do
|
||||
it 'creates the http integrations from the alert services', :aggregate_failures do
|
||||
expect { migrate! }.to change { http_integrations.count }.by(1)
|
||||
|
||||
http_integration = http_integrations.last
|
||||
expect(http_integration.project_id).to eq(alert_service.project_id)
|
||||
expect(http_integration.encrypted_token).to eq(alert_service_data.encrypted_token)
|
||||
expect(http_integration.encrypted_token_iv).to eq(alert_service_data.encrypted_token_iv)
|
||||
expect(http_integration.active).to eq(alert_service.active)
|
||||
expect(http_integration.name).to eq(described_class::SERVICE_NAMES_IDENTIFIER[:name])
|
||||
expect(http_integration.endpoint_identifier).to eq(described_class::SERVICE_NAMES_IDENTIFIER[:identifier])
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe AlertManagement::SyncAlertServiceDataService do
|
||||
let_it_be(:alerts_service) do
|
||||
AlertsService.skip_callback(:save, :after, :update_http_integration)
|
||||
service = create(:alerts_service, :active)
|
||||
AlertsService.set_callback(:save, :after, :update_http_integration)
|
||||
|
||||
service
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:execute) { described_class.new(alerts_service).execute }
|
||||
|
||||
context 'without http integration' do
|
||||
it 'creates the integration' do
|
||||
expect { execute }
|
||||
.to change { AlertManagement::HttpIntegration.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns a success' do
|
||||
expect(subject.success?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'existing legacy http integration' do
|
||||
let_it_be(:integration) { create(:alert_management_http_integration, :legacy, project: alerts_service.project) }
|
||||
|
||||
it 'updates the integration' do
|
||||
expect { execute }
|
||||
.to change { integration.reload.encrypted_token }.to(alerts_service.data.encrypted_token)
|
||||
.and change { integration.encrypted_token_iv }.to(alerts_service.data.encrypted_token_iv)
|
||||
end
|
||||
|
||||
it 'returns a success' do
|
||||
expect(subject.success?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'existing other http integration' do
|
||||
let_it_be(:integration) { create(:alert_management_http_integration, project: alerts_service.project) }
|
||||
|
||||
it 'creates the integration' do
|
||||
expect { execute }
|
||||
.to change { AlertManagement::HttpIntegration.count }.by(1)
|
||||
end
|
||||
|
||||
it 'returns a success' do
|
||||
expect(subject.success?).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
spec/support/helpers/features/members_table_helpers.rb
Normal file
33
spec/support/helpers/features/members_table_helpers.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Spec
|
||||
module Support
|
||||
module Helpers
|
||||
module Features
|
||||
module MembersHelpers
|
||||
def members_table
|
||||
page.find('[data-testid="members-table"]')
|
||||
end
|
||||
|
||||
def all_rows
|
||||
page.within(members_table) do
|
||||
page.all('tbody > tr')
|
||||
end
|
||||
end
|
||||
|
||||
def first_row
|
||||
all_rows[0]
|
||||
end
|
||||
|
||||
def second_row
|
||||
all_rows[1]
|
||||
end
|
||||
|
||||
def invite_users_form
|
||||
page.find('[data-testid="invite-users-form"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'Maintainer manages access requests' do
|
||||
include Spec::Support::Helpers::Features::MembersHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:maintainer) { create(:user) }
|
||||
|
||||
|
@ -26,7 +28,7 @@ RSpec.shared_examples 'Maintainer manages access requests' do
|
|||
|
||||
expect_no_visible_access_request(entity, user)
|
||||
|
||||
page.within('[data-qa-selector="members_list"]') do
|
||||
page.within(members_table) do
|
||||
expect(page).to have_content user.name
|
||||
end
|
||||
end
|
||||
|
@ -35,7 +37,7 @@ RSpec.shared_examples 'Maintainer manages access requests' do
|
|||
expect_visible_access_request(entity, user)
|
||||
|
||||
# Open modal
|
||||
click_on 'Deny access request'
|
||||
click_on 'Deny access'
|
||||
|
||||
expect(page).not_to have_field "Also unassign this user from related issues and merge requests"
|
||||
|
||||
|
|
Loading…
Reference in a new issue