Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8a37720edf
commit
ff8299c65d
20 changed files with 141 additions and 64 deletions
|
@ -1,4 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import initVueAlerts from '~/vue_alerts';
|
||||
import NoEmojiValidator from '../../../emoji/no_emoji_validator';
|
||||
import LengthValidator from './length_validator';
|
||||
import OAuthRememberMe from './oauth_remember_me';
|
||||
|
@ -19,4 +20,5 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
// Save the URL fragment from the current window location. This will be present if the user was
|
||||
// redirected to sign-in after attempting to access a protected URL that included a fragment.
|
||||
preserveUrlFragment(window.location.hash);
|
||||
initVueAlerts();
|
||||
});
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
<script>
|
||||
/* eslint-disable vue/no-v-html */
|
||||
import { GlAlert } from '@gitlab/ui';
|
||||
import { GlAlert, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'DismissibleAlert',
|
||||
components: {
|
||||
GlAlert,
|
||||
},
|
||||
directives: {
|
||||
SafeHtml,
|
||||
},
|
||||
props: {
|
||||
html: {
|
||||
type: String,
|
||||
|
@ -28,6 +31,6 @@ export default {
|
|||
|
||||
<template>
|
||||
<gl-alert v-if="!isDismissed" v-bind="$attrs" @dismiss="dismiss" v-on="$listeners">
|
||||
<div v-html="html"></div>
|
||||
<div v-safe-html="html"></div>
|
||||
</gl-alert>
|
||||
</template>
|
||||
|
|
|
@ -13,8 +13,16 @@ class Groups::ApplicationController < ApplicationController
|
|||
before_action :set_sorting
|
||||
requires_cross_project_access
|
||||
|
||||
helper_method :can_manage_members?
|
||||
|
||||
private
|
||||
|
||||
def can_manage_members?(group = @group)
|
||||
strong_memoize(:can_manage_members) do
|
||||
can?(current_user, :admin_group_member, group)
|
||||
end
|
||||
end
|
||||
|
||||
def group
|
||||
@group ||= find_routable!(Group, params[:group_id] || params[:id])
|
||||
end
|
||||
|
|
|
@ -22,8 +22,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
feature_category :authentication_and_authorization
|
||||
|
||||
helper_method :can_manage_members?
|
||||
|
||||
def index
|
||||
@sort = params[:sort].presence || sort_value_name
|
||||
|
||||
|
@ -53,12 +51,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
|||
|
||||
private
|
||||
|
||||
def can_manage_members?
|
||||
strong_memoize(:can_manage_members) do
|
||||
can?(current_user, :admin_group_member, @group)
|
||||
end
|
||||
end
|
||||
|
||||
def present_invited_members(invited_members)
|
||||
present_members(invited_members
|
||||
.page(params[:invited_members_page])
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
- if can?(current_user, :admin_group_member, group)
|
||||
.js-invite-members-modal{ data: { id: group.id,
|
||||
name: group.name,
|
||||
is_project: 'false',
|
||||
access_levels: GroupMember.access_level_roles.to_json,
|
||||
default_access_level: Gitlab::Access::GUEST,
|
||||
help_link: help_page_url('user/permissions') }.merge(group_select_data(group)) }
|
||||
- return unless can_manage_members?(group)
|
||||
|
||||
.js-invite-members-modal{ data: { id: group.id,
|
||||
name: group.name,
|
||||
is_project: 'false',
|
||||
access_levels: GroupMember.access_level_roles.to_json,
|
||||
default_access_level: Gitlab::Access::GUEST,
|
||||
help_link: help_page_url('user/permissions') }.merge(group_select_data(group)) }
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
- flash.each do |key, value|
|
||||
- if key == 'toast' && value
|
||||
.js-toast-message{ data: { message: value } }
|
||||
- elsif value == I18n.t('devise.failure.unconfirmed')
|
||||
= render 'shared/confirm_your_email_alert'
|
||||
- elsif value
|
||||
%div{ class: "flash-#{key} mb-2" }
|
||||
= sprite_icon(icons[key], css_class: 'align-middle mr-1') unless icons[key].nil?
|
||||
|
|
|
@ -9,4 +9,4 @@
|
|||
event: 'click_button',
|
||||
label: 'invite_members_empty_project' } }
|
||||
|
||||
= render 'shared/issuable/invite_members_trigger', project: @project
|
||||
= render 'projects/invite_members_modal', project: @project
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
- if can_invite_members_for_project?(project)
|
||||
.js-invite-members-modal{ data: { id: project.id,
|
||||
name: project.name,
|
||||
is_project: 'true',
|
||||
access_levels: ProjectMember.access_level_roles.to_json,
|
||||
default_access_level: Gitlab::Access::GUEST,
|
||||
help_link: help_page_url('user/permissions') } }
|
||||
- return unless can_import_members?
|
||||
|
||||
.js-invite-members-modal{ data: { id: project.id,
|
||||
name: project.name,
|
||||
is_project: 'true',
|
||||
access_levels: ProjectMember.access_level_roles.to_json,
|
||||
default_access_level: Gitlab::Access::GUEST,
|
||||
help_link: help_page_url('user/permissions') } }
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
|
||||
|
||||
= render 'projects/issuable/show', issuable: @issue, api_awards_path: award_emoji_issue_api_path(@issue)
|
||||
= render 'shared/issuable/invite_members_trigger', project: @project
|
||||
= render 'projects/invite_members_modal', project: @project
|
||||
|
|
|
@ -96,5 +96,5 @@
|
|||
|
||||
#js-review-bar
|
||||
|
||||
= render 'shared/issuable/invite_members_trigger', project: @project
|
||||
= render 'projects/invite_members_modal', project: @project
|
||||
|
||||
|
|
7
app/views/shared/_confirm_your_email_alert.html.haml
Normal file
7
app/views/shared/_confirm_your_email_alert.html.haml
Normal file
|
@ -0,0 +1,7 @@
|
|||
.js-vue-alert{ 'v-cloak': true,
|
||||
data: { dismissible: 'true',
|
||||
title: _('Please confirm your email address'),
|
||||
primary_button_text: _('Resend confirmation email'),
|
||||
primary_button_link: new_user_confirmation_path,
|
||||
variant: 'warning'} }
|
||||
= (_("To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select %{strongStart}Resend confirmation email.%{strongEnd}") % { strongStart: '<strong>', strongEnd: '</strong>' }).html_safe
|
|
@ -1,8 +0,0 @@
|
|||
- return unless can_import_members?
|
||||
|
||||
.js-invite-members-modal{ data: { id: project.id,
|
||||
name: project.name,
|
||||
is_project: 'true',
|
||||
access_levels: ProjectMember.access_level_roles.to_json,
|
||||
default_access_level: Gitlab::Access::GUEST,
|
||||
help_link: help_page_url('user/permissions') } }
|
|
@ -31,7 +31,7 @@ sent to the primary (unless necessary), the primary (`db3`) hardly has any load.
|
|||
|
||||
## Requirements
|
||||
|
||||
For load balancing to work you will need at least PostgreSQL 11 or newer,
|
||||
For load balancing to work, you need at least PostgreSQL 11 or newer,
|
||||
[**MySQL is not supported**](../install/requirements.md#database). You also need to make sure that you have
|
||||
at least 1 secondary in [hot standby](https://www.postgresql.org/docs/11/hot-standby.html) mode.
|
||||
|
||||
|
@ -42,7 +42,7 @@ you should put a load balancer in front of every database, and have GitLab conne
|
|||
to those load balancers.
|
||||
|
||||
For example, say you have a primary (`db1.gitlab.com`) and two secondaries,
|
||||
`db2.gitlab.com` and `db3.gitlab.com`. For this setup you will need to have 3
|
||||
`db2.gitlab.com` and `db3.gitlab.com`. For this setup, you need to have 3
|
||||
load balancers, one for every host. For example:
|
||||
|
||||
- `primary.gitlab.com` forwards to `db1.gitlab.com`
|
||||
|
@ -56,7 +56,7 @@ means forwarding should now happen as follows:
|
|||
- `secondary1.gitlab.com` forwards to `db1.gitlab.com`
|
||||
- `secondary2.gitlab.com` forwards to `db3.gitlab.com`
|
||||
|
||||
GitLab does not take care of this for you, so you will need to do so yourself.
|
||||
GitLab does not take care of this for you, so you need to do so yourself.
|
||||
|
||||
Finally, load balancing requires that GitLab can connect to all hosts using the
|
||||
same credentials and port as configured in the
|
||||
|
@ -72,7 +72,7 @@ different ports or credentials for different hosts is not supported.
|
|||
## Enabling load balancing
|
||||
|
||||
For the environment in which you want to use load balancing, you'll need to add
|
||||
the following. This will balance the load between `host1.example.com` and
|
||||
the following. This balances the load between `host1.example.com` and
|
||||
`host2.example.com`.
|
||||
|
||||
**In Omnibus installations:**
|
||||
|
@ -176,15 +176,15 @@ The following options can be set:
|
|||
| `disconnect_timeout` | The time in seconds after which an old connection is closed, after the list of hosts was updated. | 120 |
|
||||
| `use_tcp` | Lookup DNS resources using TCP instead of UDP | false |
|
||||
|
||||
If `record_type` is set to `SRV`, GitLab will continue to use a round-robin algorithm
|
||||
and will ignore the `weight` and `priority` in the record. Since SRV records usually
|
||||
return hostnames instead of IPs, GitLab will look for the IPs of returned hostnames
|
||||
If `record_type` is set to `SRV`, then GitLab continues to use round-robin algorithm
|
||||
and ignores the `weight` and `priority` in the record. Since SRV records usually
|
||||
return hostnames instead of IPs, GitLab needs to look for the IPs of returned hostnames
|
||||
in the additional section of the SRV response. If no IP is found for a hostname, GitLab
|
||||
will query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA
|
||||
needs to query the configured `nameserver` for ANY record for each such hostname looking for A or AAAA
|
||||
records, eventually dropping this hostname from rotation if it can't resolve its IP.
|
||||
|
||||
The `interval` value specifies the _minimum_ time between checks. If the A
|
||||
record has a TTL greater than this value, then service discovery will honor said
|
||||
record has a TTL greater than this value, then service discovery honors said
|
||||
TTL. For example, if the TTL of the A record is 90 seconds, then service
|
||||
discovery waits at least 90 seconds before checking the A record again.
|
||||
|
||||
|
|
|
@ -102,6 +102,30 @@ curl --request PUT \
|
|||
"https://gitlab.example.com/api/v4/projects/1/packages/nuget"
|
||||
```
|
||||
|
||||
## Upload a symbol package file
|
||||
|
||||
> Introduced in GitLab 12.8.
|
||||
|
||||
Upload a NuGet symbol package file (`.snupkg`):
|
||||
|
||||
```plaintext
|
||||
PUT projects/:id/packages/nuget/symbolpackage
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ----------------- | ------ | -------- | ----------- |
|
||||
| `id` | string | yes | The ID or full path of the project. |
|
||||
| `package_name` | string | yes | The name of the package. |
|
||||
| `package_version` | string | yes | The version of the package. |
|
||||
| `package_filename`| string | yes | The name of the file. |
|
||||
|
||||
```shell
|
||||
curl --request PUT \
|
||||
--upload-file path/to/mynugetpkg.1.3.0.17.snupkg \
|
||||
--user <username>:<personal_access_token> \
|
||||
"https://gitlab.example.com/api/v4/projects/1/packages/nuget/symbolpackage"
|
||||
```
|
||||
|
||||
## Route prefix
|
||||
|
||||
For the remaining routes, there are two sets of identical routes that each make requests in
|
||||
|
@ -193,6 +217,11 @@ Example response:
|
|||
"@id": "https://gitlab.example.com/api/v4/projects/1/packages/nuget",
|
||||
"@type": "PackagePublish/2.0.0",
|
||||
"comment": "Push and delete (or unlist) packages."
|
||||
},
|
||||
{
|
||||
"@id": "https://gitlab.example.com/api/v4/projects/1/packages/nuget/symbolpackage",
|
||||
"@type": "SymbolPackagePublish/4.9.0",
|
||||
"comment": "Push symbol packages."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ See also:
|
|||
|
||||
Learn more about:
|
||||
|
||||
- [Why you might chose GitLab CI/CD](https://about.gitlab.com/blog/2016/10/17/gitlab-ci-oohlala/).
|
||||
- [Why you might choose GitLab CI/CD](https://about.gitlab.com/blog/2016/10/17/gitlab-ci-oohlala/).
|
||||
- [Reasons you might migrate from another platform](https://about.gitlab.com/blog/2016/07/22/building-our-web-app-on-gitlab-ci/).
|
||||
- [5 Teams that made the switch to GitLab CI/CD](https://about.gitlab.com/blog/2019/04/25/5-teams-that-made-the-switch-to-gitlab-ci-cd/)
|
||||
|
||||
|
|
|
@ -39,6 +39,13 @@ and has its own dedicated IP address (`192.237.158.143`).
|
|||
|
||||
The IP address for `mg.gitlab.com` is subject to change at any time.
|
||||
|
||||
### Service Desk custom mailbox
|
||||
|
||||
On GitLab.com there's a mailbox configured for Service Desk with the email adress:
|
||||
`contact-project+%{key}@incoming.gitlab.com`. To use this mailbox, configure the
|
||||
[custom suffix](../project/service_desk.md#configuring-a-custom-email-address-suffix) in project
|
||||
settings.
|
||||
|
||||
## Backups
|
||||
|
||||
[See our backup strategy](https://about.gitlab.com/handbook/engineering/infrastructure/production/#backups).
|
||||
|
|
|
@ -24290,6 +24290,9 @@ msgstr ""
|
|||
msgid "Please complete your profile with email address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please confirm your email address"
|
||||
msgstr ""
|
||||
|
||||
msgid "Please contact an admin to register runners."
|
||||
msgstr ""
|
||||
|
||||
|
@ -33895,6 +33898,9 @@ msgstr ""
|
|||
msgid "To connect an SVN repository, check out %{svn_link}."
|
||||
msgstr ""
|
||||
|
||||
msgid "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select %{strongStart}Resend confirmation email.%{strongEnd}"
|
||||
msgstr ""
|
||||
|
||||
msgid "To define internal users, first enable new users set to external"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ RSpec.describe 'Login' do
|
|||
describe 'with an unconfirmed email address' do
|
||||
let!(:user) { create(:user, confirmed_at: nil) }
|
||||
let(:grace_period) { 2.days }
|
||||
let(:alert_title) { 'Please confirm your email address' }
|
||||
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
|
||||
|
||||
before do
|
||||
stub_application_setting(send_user_confirmation_email: true)
|
||||
|
@ -109,13 +111,14 @@ RSpec.describe 'Login' do
|
|||
|
||||
gitlab_sign_in(user)
|
||||
|
||||
expect(page).not_to have_content(I18n.t('devise.failure.unconfirmed'))
|
||||
expect(page).not_to have_content(alert_title)
|
||||
expect(page).not_to have_content(alert_message)
|
||||
expect(page).not_to have_link('Resend confirmation email', href: new_user_confirmation_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the confirmation grace period is expired' do
|
||||
it 'prevents the user from logging in and renders a resend confirmation email link' do
|
||||
it 'prevents the user from logging in and renders a resend confirmation email link', :js do
|
||||
travel_to((grace_period + 1.day).from_now) do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_unauthenticated_counter)
|
||||
|
@ -123,7 +126,8 @@ RSpec.describe 'Login' do
|
|||
|
||||
gitlab_sign_in(user)
|
||||
|
||||
expect(page).to have_content(I18n.t('devise.failure.unconfirmed'))
|
||||
expect(page).to have_content(alert_title)
|
||||
expect(page).to have_content(alert_message)
|
||||
expect(page).to have_link('Resend confirmation email', href: new_user_confirmation_path)
|
||||
end
|
||||
end
|
||||
|
@ -889,6 +893,8 @@ RSpec.describe 'Login' do
|
|||
context 'when sending confirmation email and not yet confirmed' do
|
||||
let!(:user) { create(:user, confirmed_at: nil) }
|
||||
let(:grace_period) { 2.days }
|
||||
let(:alert_title) { 'Please confirm your email address' }
|
||||
let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
|
||||
|
||||
before do
|
||||
stub_application_setting(send_user_confirmation_email: true)
|
||||
|
@ -906,7 +912,7 @@ RSpec.describe 'Login' do
|
|||
end
|
||||
|
||||
context "when not having confirmed within Devise's allow_unconfirmed_access_for time" do
|
||||
it 'does not allow login and shows a flash alert to confirm the email address' do
|
||||
it 'does not allow login and shows a flash alert to confirm the email address', :js do
|
||||
travel_to((grace_period + 1.day).from_now) do
|
||||
expect(authentication_metrics)
|
||||
.to increment(:user_unauthenticated_counter)
|
||||
|
@ -915,7 +921,9 @@ RSpec.describe 'Login' do
|
|||
gitlab_sign_in(user)
|
||||
|
||||
expect(current_path).to eq new_user_session_path
|
||||
expect(page).to have_content(I18n.t('devise.failure.unconfirmed'))
|
||||
expect(page).to have_content(alert_title)
|
||||
expect(page).to have_content(alert_message)
|
||||
expect(page).to have_link('Resend confirmation email', href: new_user_confirmation_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,8 +28,8 @@ describe('VueAlerts', () => {
|
|||
alerts
|
||||
.map(
|
||||
(x) => `
|
||||
<div class="js-vue-alert"
|
||||
data-dismissible="${x.dismissible}"
|
||||
<div class="js-vue-alert"
|
||||
data-dismissible="${x.dismissible}"
|
||||
data-title="${x.title}"
|
||||
data-primary-button-text="${x.primaryButtonText}"
|
||||
data-primary-button-link="${x.primaryButtonLink}"
|
||||
|
|
|
@ -5,18 +5,12 @@ import DismissibleAlert from '~/vue_shared/components/dismissible_alert.vue';
|
|||
const TEST_HTML = 'Hello World! <strong>Foo</strong>';
|
||||
|
||||
describe('vue_shared/components/dismissible_alert', () => {
|
||||
const testAlertProps = {
|
||||
primaryButtonText: 'Lorem ipsum',
|
||||
primaryButtonLink: '/lorem/ipsum',
|
||||
};
|
||||
|
||||
let wrapper;
|
||||
|
||||
const createComponent = (props = {}) => {
|
||||
wrapper = shallowMount(DismissibleAlert, {
|
||||
propsData: {
|
||||
html: TEST_HTML,
|
||||
...testAlertProps,
|
||||
...props,
|
||||
},
|
||||
});
|
||||
|
@ -28,16 +22,13 @@ describe('vue_shared/components/dismissible_alert', () => {
|
|||
|
||||
const findAlert = () => wrapper.find(GlAlert);
|
||||
|
||||
describe('with default', () => {
|
||||
describe('default', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('shows alert', () => {
|
||||
const alert = findAlert();
|
||||
|
||||
expect(alert.exists()).toBe(true);
|
||||
expect(alert.props()).toEqual(expect.objectContaining(testAlertProps));
|
||||
expect(findAlert().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('shows given HTML', () => {
|
||||
|
@ -54,4 +45,32 @@ describe('vue_shared/components/dismissible_alert', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with additional props', () => {
|
||||
const testAlertProps = {
|
||||
dismissible: true,
|
||||
title: 'Mock Title',
|
||||
primaryButtonText: 'Lorem ipsum',
|
||||
primaryButtonLink: '/lorem/ipsum',
|
||||
variant: 'warning',
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
createComponent(testAlertProps);
|
||||
});
|
||||
|
||||
it('passes other props', () => {
|
||||
expect(findAlert().props()).toEqual(expect.objectContaining(testAlertProps));
|
||||
});
|
||||
});
|
||||
|
||||
describe('with unsafe HTML', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ html: '<a onclick="alert("XSS")">Link</a>' });
|
||||
});
|
||||
|
||||
it('removes unsafe HTML', () => {
|
||||
expect(findAlert().html()).toContain('<a>Link</a>');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue