Commit 662276be authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '11-0-stable-prepare-rc11' into '11-0-stable'

Prepare 11.0 RC11 release

See merge request !19761
parents 70891b79 da179248
Pipeline #23801689 passed with stages
in 31 minutes and 38 seconds
......@@ -55,7 +55,8 @@ class List {
entityType = 'assignee_id';
}
return gl.boardService.createList(this.label.id)
return gl.boardService
.createList(entity.id, entityType)
.then(res => res.data)
.then(data => {
this.id = data.id;
......
......@@ -56,7 +56,7 @@ export default class MilestoneSelect {
if (issueUpdateURL) {
milestoneLinkTemplate = _.template(
'<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
'<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
);
milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
}
......
......@@ -86,6 +86,7 @@ export default {
<img
v-tooltip
class="avatar"
data-boundary="window"
:class="{
lazy: lazy,
[avatarSizeClass]: true,
......
......@@ -94,6 +94,7 @@ hr {
}
.form-group.row .col-form-label {
padding-top: 0;
// Bootstrap 4 aligns labels to the left
// for horizontal forms
@include media-breakpoint-up(md) {
......
......@@ -268,6 +268,8 @@
.navbar-sub-nav,
.navbar-nav {
align-items: center;
> li {
> a:hover,
> a:focus {
......
......@@ -186,6 +186,7 @@
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
flex-wrap: nowrap;
&::-webkit-scrollbar {
display: none;
......
......@@ -230,6 +230,8 @@
}
.scrolling-tabs-container {
position: relative;
.merge-request-tabs-container & {
overflow: hidden;
}
......
......@@ -58,7 +58,7 @@ table {
display: none;
}
table,
&,
tbody,
td {
display: block;
......
......@@ -58,7 +58,7 @@
}
.color-label {
padding: $gl-padding-4 $grid-size;
padding: 0 $grid-size;
line-height: 16px;
border-radius: $label-border-radius;
color: $white-light;
......@@ -112,6 +112,10 @@
}
}
}
.color-label {
padding: $gl-padding-4 $grid-size;
}
}
.prioritized-labels {
......
......@@ -121,10 +121,6 @@
background: transparent;
border: 0;
outline: 0;
@include media-breakpoint-up(sm) {
right: 160px;
}
}
.flex-project-members-panel {
......
......@@ -678,6 +678,7 @@
.merge-request-tabs {
display: flex;
flex-wrap: nowrap;
margin-bottom: 0;
padding: 0;
}
......
......@@ -354,12 +354,6 @@
min-width: 200px;
}
.deploy-keys {
.scrolling-tabs-container {
position: relative;
}
}
.deploy-key {
// Ensure that the fingerprint does not overflow on small screens
.fingerprint {
......
......@@ -3,6 +3,9 @@ class RegistrationsController < Devise::RegistrationsController
include AcceptsPendingInvitations
before_action :whitelist_query_limiting, only: [:destroy]
before_action :ensure_terms_accepted,
if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms? },
only: [:create]
def new
redirect_to(new_user_session_path)
......@@ -18,7 +21,9 @@ class RegistrationsController < Devise::RegistrationsController
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
accept_pending_invitations
super
super do |new_user|
persist_accepted_terms_if_required(new_user)
end
else
flash[:alert] = 'There was an error with the reCAPTCHA. Please solve the reCAPTCHA again.'
flash.delete :recaptcha_error
......@@ -40,6 +45,16 @@ class RegistrationsController < Devise::RegistrationsController
protected
def persist_accepted_terms_if_required(new_user)
return unless new_user.persisted?
return unless Gitlab::CurrentSettings.current_application_settings.enforce_terms?
if terms_accepted?
terms = ApplicationSetting::Term.latest
Users::RespondToTermsService.new(new_user, terms).execute(accepted: true)
end
end
def destroy_confirmation_valid?
if current_user.confirm_deletion_with_password?
current_user.valid_password?(params[:password])
......@@ -91,4 +106,14 @@ class RegistrationsController < Devise::RegistrationsController
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42380')
end
def ensure_terms_accepted
return if terms_accepted?
redirect_to new_user_session_path, alert: _('You must accept our Terms of Service and privacy policy in order to register an account')
end
def terms_accepted?
Gitlab::Utils.to_boolean(params[:terms_opt_in])
end
end
......@@ -2,6 +2,7 @@ module Users
class TermsController < ApplicationController
include InternalRedirect
skip_before_action :authenticate_user!
skip_before_action :enforce_terms!
skip_before_action :check_password_expiration
skip_before_action :check_two_factor_requirement
......@@ -14,7 +15,7 @@ module Users
def index
@redirect = redirect_path
if @term.accepted_by_user?(current_user)
if current_user && @term.accepted_by_user?(current_user)
flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}"
end
end
......
= form_for @application_setting, url: admin_application_settings_path do |f|
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'fieldset-form' } do |f|
= form_errors(@application_setting)
%fieldset
......@@ -7,13 +7,13 @@
.form-check
= f.check_box :enforce_terms, class: 'form-check-input'
= f.label :enforce_terms, class: 'form-check-label' do
= _("Require all users to accept Terms of Service when they access GitLab.")
= _("Require all users to accept Terms of Service and Privacy Policy when they access GitLab.")
.form-text.text-muted
= _("When enabled, users cannot use GitLab until the terms have been accepted.")
.form-group.row
.col-sm-12
= f.label :terms do
= _("Terms of Service Agreement")
= _("Terms of Service Agreement and Privacy Policy")
.col-sm-12
= f.text_area :terms, class: 'form-control', rows: 8
.form-text.text-muted
......
......@@ -50,11 +50,11 @@
%section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
= _('Terms of Service')
= _('Terms of Service and Privacy Policy')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= _('Include a Terms of Service agreement that all users must accept.')
= _('Include a Terms of Service agreement and Privacy Policy that all users must accept.')
.settings-content
= render 'terms'
......
......@@ -22,6 +22,13 @@
= f.label :password
= f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters."
%p.gl-field-hint Minimum length is #{@minimum_password_length} characters
- if Gitlab::CurrentSettings.current_application_settings.enforce_terms?
.form-group
= check_box_tag :terms_opt_in, '1', false, required: true
= label_tag :terms_opt_in do
- terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank"
- accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link }
= accept_terms_label.html_safe
%div
- if Gitlab::Recaptcha.enabled?
= recaptcha_tags
......
......@@ -25,9 +25,10 @@
%span.badge= @members.total_count
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form flex-project-members-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false }
%button.member-search-btn{ type: "submit", "aria-label" => "Submit search" }
= icon("search")
.position-relative.append-right-8
= search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false }
%button.member-search-btn{ type: "submit", "aria-label" => "Submit search" }
= icon("search")
- if can_manage_members
= render 'shared/members/filter_2fa_dropdown'
= render 'shared/members/sort_dropdown'
......
......@@ -32,26 +32,25 @@
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.nav.nav-tabs
%ul.merge-request-tabs.nav-tabs.nav
%li.notes-tab
= tab_link_for @merge_request, :show, force_link: @commit.present? do
Discussion
%span.badge.badge-pill= @merge_request.related_notes.user.count
- if @merge_request.source_project
%li.commits-tab
= tab_link_for @merge_request, :commits do
Commits
%span.badge.badge-pill= @commits_count
- if @pipelines.any?
%li.pipelines-tab
= tab_link_for @merge_request, :pipelines do
Pipelines
%span.badge.badge-pill.js-pipelines-mr-count= @pipelines.size
%li.diffs-tab
= tab_link_for @merge_request, :diffs do
Changes
%span.badge.badge-pill= @merge_request.diff_size
%ul.merge-request-tabs.nav-tabs.nav.nav-links.scrolling-tabs
%li.notes-tab
= tab_link_for @merge_request, :show, force_link: @commit.present? do
Discussion
%span.badge.badge-pill= @merge_request.related_notes.user.count
- if @merge_request.source_project
%li.commits-tab
= tab_link_for @merge_request, :commits do
Commits
%span.badge.badge-pill= @commits_count
- if @pipelines.any?
%li.pipelines-tab
= tab_link_for @merge_request, :pipelines do
Pipelines
%span.badge.badge-pill.js-pipelines-mr-count= @pipelines.size
%li.diffs-tab
= tab_link_for @merge_request, :diffs do
Changes
%span.badge.badge-pill= @merge_request.diff_size
- if has_vue_discussions_cookie?
#js-vue-discussion-counter
......
......@@ -9,9 +9,10 @@
%span.badge.badge-pill= members.total_count
= form_tag project_project_members_path(project), method: :get, class: 'form-inline member-search-form flex-project-members-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false }
%button.member-search-btn{ type: "submit", "aria-label" => "Submit search" }
= icon("search")
.position-relative
= search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false }
%button.member-search-btn{ type: "submit", "aria-label" => "Submit search" }
= icon("search")
= render 'shared/members/sort_dropdown'
%ul.content-list.members-list
= render partial: 'shared/members/member', collection: members, as: :member
......@@ -2,16 +2,17 @@
.card-body.rendered-terms
= markdown_field(@term, :terms)
.card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term)
.float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms')
- else
.pull-right
= link_to root_path, class: 'btn btn-success prepend-left-8' do
= _('Continue')
- if can?(current_user, :decline_terms, @term)
.float-right
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
= _('Decline and sign out')
- if current_user
.card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term)
.float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms')
- else
.pull-right
= link_to root_path, class: 'btn btn-success prepend-left-8' do
= _('Continue')
- if can?(current_user, :decline_terms, @term)
.float-right
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
= _('Decline and sign out')
---
title: Users can accept terms during registration
merge_request: 19583
author:
type: other
---
title: Restore API v3 user endpoint
merge_request:
author:
type: changed
......@@ -20,6 +20,19 @@ When an admin enables this feature, they will automattically be
directed to the page to accept the terms themselves. After they
accept, they will be directed back to the settings page.
## New registrations
When this feature is enabled, a checkbox will be available in the
sign-up form.
![Sign up form](img/sign_up_terms.png)
This checkbox will be required during sign up.
Users can review the terms entered in the admin panel before
accepting. The page will be opened in a new window so they can
continue their registration afterwards.
## Accepting terms
When this feature was enabled, the users that have not accepted the
......
......@@ -237,13 +237,15 @@ Issue Board, that is create/delete lists and drag issues around.
## Group Issue Board
>Introduced in GitLab 10.6
> Introduced in [GitLab 10.6](https://about.gitlab.com/2018/03/22/gitlab-10-6-released/#single-group-issue-board-in-core-and-free)
Group issue board is analogous to project-level issue board and it is accessible at the group
navigation level. A group-level issue board allows you to view all issues from all projects in that group or descendant subgroups. Similarly, you can only filter by group labels for these
boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
group-level objects are available.
One group issue board per group was made available in GitLab 10.6 Core after multiple group issue boards were originally introduced in [GitLab 10.0 Premium](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards).
## Features per tier
Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/), as shown in the following table:
......
......@@ -42,5 +42,26 @@ list.
An additional review mode is available when you open a merge request, which
shows you a preview of the merge request diff if you commit your changes.
## View CI job logs
> [Introduced in](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19279) [GitLab Core][ce] 11.0.
The Web IDE can be used to quickly fix failing tests by opening the branch or
merge request in the Web IDE and opening the logs of the failed job. The status
of all jobs for the most recent pipeline and job traces for the current commit
can be accessed by clicking the **Pipelines** button in the top right.
The pipeline status is also shown at all times in the status bar in the bottom
left.
## Switching merge requests
> [Introduced in](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19318) [GitLab Core][ce] 11.0.
Switching between your authored and assigned merge requests can be done without
leaving the Web IDE. Click the project name in the top left to open a list of
merge requests. You will need to commit or discard all your changes before
switching to a different merge request.
[ce]: https://about.gitlab.com/pricing/
[ee]: https://about.gitlab.com/pricing/
......@@ -412,6 +412,10 @@ module API
expose :state, :created_at, :updated_at
expose :due_date
expose :start_date
expose :web_url do |milestone, _options|
Gitlab::UrlBuilder.build(milestone)
end
end
class IssueBasic < ProjectEntity
......
......@@ -531,18 +531,22 @@ module API
authenticate!
end
desc 'Get the currently authenticated user' do
success Entities::UserPublic
end
get do
entity =
if current_user.admin?
Entities::UserWithAdmin
else
Entities::UserPublic
end
# Enabling /user endpoint for the v3 version to allow oauth
# authentication through this endpoint.
version %w(v3 v4), using: :path do
desc 'Get the currently authenticated user' do
success Entities::UserPublic
end
get do
entity =
if current_user.admin?
Entities::UserWithAdmin
else
Entities::UserPublic
end
present current_user, with: entity
present current_user, with: entity
end
end
desc "Get the currently authenticated user's SSH keys" do
......
......@@ -65,7 +65,7 @@ module Banzai
# We don't support IID lookups for group milestones, because IIDs can
# clash between group and project milestones.
if project.group && !params[:iid]
finder_params[:group_ids] = [project.group.id]
finder_params[:group_ids] = project.group.self_and_ancestors.select(:id)
end
MilestonesFinder.new(finder_params).find_by(params)
......
......@@ -26,6 +26,8 @@ module Gitlab
project_snippet_url(object.project, object)
when Snippet
snippet_url(object)
when Milestone
milestone_url(object)
else
raise NotImplementedError.new("No URL builder defined for #{object.class}")
end
......
This diff is collapsed.
require 'spec_helper'
describe RegistrationsController do
include TermsHelper
describe '#create' do
let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } }
......@@ -67,6 +69,25 @@ describe RegistrationsController do
expect(flash[:notice]).to include 'Welcome! You have signed up successfully.'
end
end
context 'when terms are enforced' do
before do
enforce_terms
end
it 'redirects back with a notice when the checkbox was not checked' do
post :create, user_params
expect(flash[:alert]).to match /you must accept our terms/i
end
it 'creates the user with agreement when terms are accepted' do
post :create, user_params.merge(terms_opt_in: '1')
expect(subject.current_user).to be_present
expect(subject.current_user.terms_accepted?).to be(true)
end
end
end
describe '#destroy' do
......
......@@ -94,7 +94,7 @@ feature 'Admin updates settings' do
accept_terms(admin)
page.within('.as-terms') do
check 'Require all users to accept Terms of Service when they access GitLab.'
check 'Require all users to accept Terms of Service and Privacy Policy when they access GitLab.'
fill_in 'Terms of Service Agreement', with: 'Be nice!'
click_button 'Save changes'
end
......
......@@ -140,7 +140,7 @@ describe 'Signup' do
enforce_terms
end
it 'asks the user to accept terms before going to the dashboard' do
it 'requires the user to check the checkbox' do
visit root_path
fill_in 'new_user_name', with: new_user.name
......@@ -148,11 +148,24 @@ describe 'Signup' do
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password
click_button "Register"
expect_to_be_on_terms_page
click_button 'Register'
expect(current_path).to eq new_user_session_path
expect(page).to have_content(/you must accept our terms of service/i)
end
it 'asks the user to accept terms before going to the dashboard' do
visit root_path
fill_in 'new_user_name', with: new_user.name
fill_in 'new_user_username', with: new_user.username
fill_in 'new_user_email', with: new_user.email
fill_in 'new_user_email_confirmation', with: new_user.email
fill_in 'new_user_password', with: new_user.password
check :terms_opt_in
click_button 'Accept terms'
click_button "Register"
expect(current_path).to eq dashboard_projects_path
end
......
......@@ -3,12 +3,10 @@ require 'spec_helper'
describe 'Users > Terms' do
include TermsHelper
let(:user) { create(:user) }
let!(:term) { create(:term, terms: 'By accepting, you promise to be nice!') }
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(user)
end
it 'shows the terms' do
......@@ -17,102 +15,119 @@ describe 'Users > Terms' do
expect(page).to have_content('By accepting, you promise to be nice!')
end
context 'declining the terms' do
it 'returns the user to the app' do
visit terms_path
it 'does not show buttons to accept, decline or sign out', :aggregate_failures do
visit terms_path
expect(page).not_to have_css('.footer-block')
expect(page).not_to have_content('Accept terms')
expect(page).not_to have_content('Decline and sign out')
expect(page).not_to have_content('Continue')
end
click_button 'Decline and sign out'
context 'when signed in' do
let(:user) { create(:user) }
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(false)
before do
sign_in(user)
end
end
context 'accepting the terms' do
it 'returns the user to the app' do
visit terms_path
context 'declining the terms' do
it 'returns the user to the app' do
visit terms_path
click_button 'Accept terms'
click_button 'Decline and sign out'
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(true)
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(false)
end
end
end
context 'when the user has already accepted the terms' do
before do
accept_terms(user)
context 'accepting the terms' do
it 'returns the user to the app' do
visit terms_path
click_button 'Accept terms'
expect(page).not_to have_content(term.terms)
expect(user.reload.terms_accepted?).to be(true)
end
end
it 'allows the user to continue to the app' do
visit terms_path
context 'when the user has already accepted the terms' do
before do
accept_terms(user)
end
it 'allows the user to continue to the app' do
visit terms_path
expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}"
expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}"
click_link 'Continue'
click_link 'Continue'
expect(current_path).to eq(root_path)
expect(current_path).to eq(root_path)
end
end
end
context 'terms were enforced while session is active', :js do
let(:project) { create(:project) }
context 'terms were enforced while session is active', :js do
let(:project) { create(:project) }
before do
project.add_developer(user)
end