Enforces terms in the web application
This enforces the terms in the web application. These cases are specced: - Logging in: When terms are enforced, and a user logs in that has not accepted the terms, they are presented with the screen. They get directed to their customized root path afterwards. - Signing up: After signing up, the first screen the user is presented with the screen to accept the terms. After they accept they are directed to the dashboard. - While a session is active: - For a GET: The user will be directed to the terms page first, after they accept the terms, they will be directed to the page they were going to - For any other request: They are directed to the terms, after they accept the terms, they are directed back to the page they came from to retry the request. Any information entered would be persisted in localstorage and available on the page.
This commit is contained in:
parent
10aa55a770
commit
7684217d68
25 changed files with 736 additions and 94 deletions
|
@ -30,7 +30,7 @@ export default class IssuableForm {
|
|||
}
|
||||
|
||||
this.initAutosave();
|
||||
this.form.on('submit', this.handleSubmit);
|
||||
this.form.on('submit:success', this.handleSubmit);
|
||||
this.form.on('click', '.btn-cancel', this.resetAutosave);
|
||||
this.initWip();
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
.terms {
|
||||
.alert-wrapper {
|
||||
min-height: $header-height + $gl-padding;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding-top: $gl-padding;
|
||||
}
|
||||
|
||||
.panel {
|
||||
.panel-heading {
|
||||
display: -webkit-flex;
|
||||
|
@ -7,17 +15,15 @@
|
|||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
margin: 5px 2px 5px -8px;
|
||||
border-radius: 4px;
|
||||
|
||||
.logo-text {
|
||||
width: 55px;
|
||||
height: 24px;
|
||||
margin: 0 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,15 +37,19 @@
|
|||
}
|
||||
|
||||
.panel-content {
|
||||
padding: 0 $gl-padding;
|
||||
padding: $gl-padding;
|
||||
|
||||
*:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
*:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer-block {
|
||||
margin: 0;
|
||||
|
||||
.btn {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,12 +13,14 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
before_action :authenticate_sessionless_user!
|
||||
before_action :authenticate_user!
|
||||
before_action :enforce_terms!, if: -> { Gitlab::CurrentSettings.current_application_settings.enforce_terms },
|
||||
unless: :peek_request?
|
||||
before_action :validate_user_service_ticket!
|
||||
before_action :check_password_expiration
|
||||
before_action :ldap_security_check
|
||||
before_action :sentry_context
|
||||
before_action :default_headers
|
||||
before_action :add_gon_variables, unless: -> { request.path.start_with?('/-/peek') }
|
||||
before_action :add_gon_variables, unless: :peek_request?
|
||||
before_action :configure_permitted_parameters, if: :devise_controller?
|
||||
before_action :require_email, unless: :devise_controller?
|
||||
|
||||
|
@ -269,6 +271,27 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def enforce_terms!
|
||||
return unless current_user
|
||||
return if current_user.terms_accepted?
|
||||
|
||||
if sessionless_user?
|
||||
render_403
|
||||
else
|
||||
# Redirect to the destination if the request is a get.
|
||||
# Redirect to the source if it was a post, so the user can re-submit after
|
||||
# accepting the terms.
|
||||
redirect_path = if request.get?
|
||||
request.fullpath
|
||||
else
|
||||
URI(request.referer).path if request.referer
|
||||
end
|
||||
|
||||
flash[:notice] = _("Please accept the Terms of Service before continuing.")
|
||||
redirect_to terms_path(redirect: redirect_path), status: :found
|
||||
end
|
||||
end
|
||||
|
||||
def import_sources_enabled?
|
||||
!Gitlab::CurrentSettings.import_sources.empty?
|
||||
end
|
||||
|
@ -342,4 +365,12 @@ class ApplicationController < ActionController::Base
|
|||
# Per https://tools.ietf.org/html/rfc5987, headers need to be ISO-8859-1, not UTF-8
|
||||
response.headers['Page-Title'] = URI.escape(page_title('GitLab'))
|
||||
end
|
||||
|
||||
def sessionless_user?
|
||||
current_user && !session.keys.include?('warden.user.user.key')
|
||||
end
|
||||
|
||||
def peek_request?
|
||||
request.path.start_with?('/-/peek')
|
||||
end
|
||||
end
|
||||
|
|
35
app/controllers/concerns/internal_redirect.rb
Normal file
35
app/controllers/concerns/internal_redirect.rb
Normal file
|
@ -0,0 +1,35 @@
|
|||
module InternalRedirect
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def safe_redirect_path(path)
|
||||
return unless path
|
||||
# Verify that the string starts with a `/` but not a double `/`.
|
||||
return unless path =~ %r{^/\w.*$}
|
||||
|
||||
uri = URI(path)
|
||||
# Ignore anything path of the redirect except for the path, querystring and,
|
||||
# fragment, forcing the redirect within the same host.
|
||||
full_path_for_uri(uri)
|
||||
rescue URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
||||
def safe_redirect_path_for_url(url)
|
||||
return unless url
|
||||
|
||||
uri = URI(url)
|
||||
safe_redirect_path(full_path_for_uri(uri)) if host_allowed?(uri)
|
||||
rescue URI::InvalidURIError
|
||||
nil
|
||||
end
|
||||
|
||||
def host_allowed?(uri)
|
||||
uri.host == request.host &&
|
||||
uri.port == request.port
|
||||
end
|
||||
|
||||
def full_path_for_uri(uri)
|
||||
path_with_query = [uri.path, uri.query].compact.join('?')
|
||||
[path_with_query, uri.fragment].compact.join("#")
|
||||
end
|
||||
end
|
|
@ -1,5 +1,8 @@
|
|||
module Users
|
||||
class TermsController < ApplicationController
|
||||
include InternalRedirect
|
||||
|
||||
skip_before_action :enforce_terms!
|
||||
before_action :terms
|
||||
|
||||
layout 'terms'
|
||||
|
@ -46,11 +49,18 @@ module Users
|
|||
end
|
||||
|
||||
def redirect_path
|
||||
referer = if request.referer && !request.referer.include?(terms_path)
|
||||
URI(request.referer).path
|
||||
end
|
||||
redirect_to_path = safe_redirect_path(params[:redirect]) || safe_redirect_path_for_url(request.referer)
|
||||
|
||||
params[:redirect] || referer || root_path
|
||||
if redirect_to_path &&
|
||||
excluded_redirect_paths.none? { |excluded| redirect_to_path.include?(excluded) }
|
||||
redirect_to_path
|
||||
else
|
||||
root_path
|
||||
end
|
||||
end
|
||||
|
||||
def excluded_redirect_paths
|
||||
[terms_path, new_user_session_path]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,17 +2,15 @@ class ApplicationSetting
|
|||
class TermPolicy < BasePolicy
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
condition(:logged_in, scope: :user) { @user }
|
||||
|
||||
condition(:current_terms, scope: :subject) do
|
||||
Gitlab::CurrentSettings.current_application_settings.latest_terms == @subject
|
||||
end
|
||||
|
||||
condition(:terms_accepted, scope: :user, score: 1) do
|
||||
condition(:terms_accepted, score: 1) do
|
||||
agreement&.accepted
|
||||
end
|
||||
|
||||
rule { logged_in & current_terms }.policy do
|
||||
rule { ~anonymous & current_terms }.policy do
|
||||
enable :accept_terms
|
||||
enable :decline_terms
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
%h4
|
||||
= _('Visibility and access controls')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
|
||||
.settings-content
|
||||
|
@ -19,7 +19,7 @@
|
|||
%h4
|
||||
= _('Account and limit settings')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Session expiration, projects limit and attachment size.')
|
||||
.settings-content
|
||||
|
@ -30,7 +30,7 @@
|
|||
%h4
|
||||
= _('Sign-up restrictions')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure the way a user creates a new account.')
|
||||
.settings-content
|
||||
|
@ -41,7 +41,7 @@
|
|||
%h4
|
||||
= _('Sign-in restrictions')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Set requirements for a user to sign-in. Enable mandatory two-factor authentication.')
|
||||
.settings-content
|
||||
|
@ -51,8 +51,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Terms of Service')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Include a Terms of Service agreement that all users must accept.')
|
||||
.settings-content
|
||||
|
@ -62,8 +62,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Help page')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Help page text and support page url.')
|
||||
.settings-content
|
||||
|
@ -73,8 +73,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Pages')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Size and domain settings for static websites')
|
||||
.settings-content
|
||||
|
@ -84,8 +84,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Continuous Integration and Deployment')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Auto DevOps, runners and job artifacts')
|
||||
.settings-content
|
||||
|
@ -95,8 +95,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Metrics - Influx')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable and configure InfluxDB metrics.')
|
||||
.settings-content
|
||||
|
@ -106,8 +106,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Metrics - Prometheus')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable and configure Prometheus metrics.')
|
||||
.settings-content
|
||||
|
@ -117,8 +117,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Profiling - Performance bar')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable the Performance Bar for a given group.')
|
||||
= link_to icon('question-circle'), help_page_path('administration/monitoring/performance/performance_bar')
|
||||
|
@ -129,8 +129,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Background jobs')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure Sidekiq job throttling.')
|
||||
.settings-content
|
||||
|
@ -140,8 +140,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Spam and Anti-bot Protection')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable reCAPTCHA or Akismet and set IP limits.')
|
||||
.settings-content
|
||||
|
@ -151,8 +151,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Abuse reports')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Set notification email for abuse reports.')
|
||||
.settings-content
|
||||
|
@ -162,8 +162,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Error Reporting and Logging')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable Sentry for error reporting and logging.')
|
||||
.settings-content
|
||||
|
@ -173,8 +173,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Repository storage')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure storage path and circuit breaker settings.')
|
||||
.settings-content
|
||||
|
@ -184,8 +184,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Repository maintenance')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure automatic git checks and housekeeping on repositories.')
|
||||
.settings-content
|
||||
|
@ -196,8 +196,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Container Registry')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Various container registry settings.')
|
||||
.settings-content
|
||||
|
@ -208,8 +208,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Koding')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Online IDE integration settings.')
|
||||
.settings-content
|
||||
|
@ -219,8 +219,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('PlantUML')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Allow rendering of PlantUML diagrams in Asciidoc documents.')
|
||||
.settings-content
|
||||
|
@ -230,8 +230,8 @@
|
|||
.settings-header#usage-statistics
|
||||
%h4
|
||||
= _('Usage statistics')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Enable or disable version check and usage ping.')
|
||||
.settings-content
|
||||
|
@ -241,8 +241,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Email')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Various email settings.')
|
||||
.settings-content
|
||||
|
@ -252,8 +252,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Gitaly')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure Gitaly timeouts.')
|
||||
.settings-content
|
||||
|
@ -263,8 +263,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Web terminal')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Set max session time for web terminal.')
|
||||
.settings-content
|
||||
|
@ -274,8 +274,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Real-time features')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Change this value to influence how frequently the GitLab UI polls for updates.')
|
||||
.settings-content
|
||||
|
@ -285,8 +285,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Performance optimization')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Various settings that affect GitLab performance.')
|
||||
.settings-content
|
||||
|
@ -296,8 +296,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('User and IP Rate Limits')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Configure limits for web and API requests.')
|
||||
.settings-content
|
||||
|
@ -307,8 +307,8 @@
|
|||
.settings-header
|
||||
%h4
|
||||
= _('Outbound requests')
|
||||
%button.btn.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
|
||||
= expanded ? _('Collapse') : _('Expand')
|
||||
%p
|
||||
= _('Allow requests to the local network from hooks and services.')
|
||||
.settings-content
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
- extra_flash_class = local_assigns.fetch(:extra_flash_class, nil)
|
||||
|
||||
.flash-container.flash-container-page
|
||||
-# We currently only support `alert`, `notice`, `success`
|
||||
- flash.each do |key, value|
|
||||
-# Don't show a flash message if the message is nil
|
||||
- if value
|
||||
%div{ class: "flash-#{key}" }
|
||||
%div{ class: (container_class) }
|
||||
%div{ class: "#{container_class} #{extra_flash_class}" }
|
||||
%span= value
|
||||
|
|
|
@ -4,17 +4,15 @@
|
|||
= render "layouts/head"
|
||||
|
||||
%body{ data: { page: body_data_page } }
|
||||
= render 'peek/bar'
|
||||
.layout-page.terms
|
||||
.content-wrapper
|
||||
.layout-page.terms{ class: page_class }
|
||||
.content-wrapper.prepend-top-0
|
||||
.mobile-overlay
|
||||
.alert-wrapper
|
||||
= render "layouts/broadcast"
|
||||
= render 'layouts/header/read_only_banner'
|
||||
= yield :flash_message
|
||||
= render "layouts/flash"
|
||||
= render "layouts/flash", extra_flash_class: 'limit-container-width'
|
||||
|
||||
%div{ class: "#{container_class}" }
|
||||
%div{ class: "#{container_class} limit-container-width" }
|
||||
.content{ id: "content-body" }
|
||||
.panel.panel-default
|
||||
.panel-heading
|
||||
|
@ -22,7 +20,7 @@
|
|||
= brand_header_logo
|
||||
- logo_text = brand_header_logo_type
|
||||
- if logo_text.present?
|
||||
%span.logo-text.hidden-xs
|
||||
%span.logo-text.hidden-xs.prepend-left-8
|
||||
= logo_text
|
||||
- if header_link?(:user_dropdown)
|
||||
.navbar-collapse.collapse
|
||||
|
@ -34,4 +32,3 @@
|
|||
.dropdown-menu-nav.dropdown-menu-align-right
|
||||
= render 'layouts/header/current_user_dropdown'
|
||||
= yield
|
||||
= yield :scripts_body
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
- redirect_params = { redirect: @redirect } if @redirect
|
||||
|
||||
.panel-content.rendered-terms
|
||||
= markdown_field(@term, :terms)
|
||||
.row-content-block.footer-block.clearfix
|
||||
|
|
5
changelogs/unreleased/bvl-enforce-terms.yml
Normal file
5
changelogs/unreleased/bvl-enforce-terms.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow admins to enforce accepting Terms of Service on an instance
|
||||
merge_request: 18570
|
||||
author:
|
||||
type: added
|
|
@ -40,6 +40,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
|
|||
[source installations](../install/installation.md#installation-from-source).
|
||||
- [Environment variables](environment_variables.md): Supported environment variables that can be used to override their defaults values in order to configure GitLab.
|
||||
- [Plugins](plugins.md): With custom plugins, GitLab administrators can introduce custom integrations without modifying GitLab's source code.
|
||||
- [Enforcing Terms of Service](../user/admin_area/settings/terms.md)
|
||||
|
||||
#### Customizing GitLab's appearance
|
||||
|
||||
|
|
BIN
doc/user/admin_area/settings/img/enforce_terms.png
Executable file
BIN
doc/user/admin_area/settings/img/enforce_terms.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 51 KiB |
BIN
doc/user/admin_area/settings/img/respond_to_terms.png
Executable file
BIN
doc/user/admin_area/settings/img/respond_to_terms.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 201 KiB |
38
doc/user/admin_area/settings/terms.md
Normal file
38
doc/user/admin_area/settings/terms.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# Enforce accepting Terms of Service
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18570)
|
||||
> in [GitLab Core](https://about.gitlab.com/pricing/) 10.8
|
||||
|
||||
## Configuration
|
||||
|
||||
When it is required for all users of the GitLab instance to accept the
|
||||
Terms of Service, this can be configured by an admin on the settings
|
||||
page:
|
||||
|
||||
![Enable enforcing Terms of Service](img/enforce_terms.png).
|
||||
|
||||
The terms itself can be entered using Markdown. For each update to the
|
||||
terms, a new version is stored. When a user accepts or declines the
|
||||
terms, GitLab will keep track of which version they accepted or
|
||||
declined.
|
||||
|
||||
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.
|
||||
|
||||
## Accepting terms
|
||||
|
||||
When this feature was enabled, the users that have not accepted the
|
||||
terms of service will be presented with a screen where they can either
|
||||
accept or decline the terms.
|
||||
|
||||
![Respond to terms](img/respond_to_terms.png)
|
||||
|
||||
When the user accepts the terms, they will be directed to where they
|
||||
were going. After a sign-in or sign-up this will most likely be the
|
||||
dashboard.
|
||||
|
||||
When the user was already logged in when the feature was turned on,
|
||||
they will be asked to accept the terms on their next interaction.
|
||||
|
||||
When a user declines the terms, they will be signed out.
|
|
@ -8,8 +8,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: gitlab 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-04-24 13:19+0000\n"
|
||||
"PO-Revision-Date: 2018-04-24 13:19+0000\n"
|
||||
"POT-Creation-Date: 2018-05-02 22:28+0200\n"
|
||||
"PO-Revision-Date: 2018-05-02 22:28+0200\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
|
@ -84,6 +84,9 @@ msgstr ""
|
|||
msgid "%{openOrClose} %{noteable}"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{percent}%% complete"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{storage_name}: failed storage access attempt on host:"
|
||||
msgid_plural "%{storage_name}: %{failed_attempts} failed storage access attempts:"
|
||||
msgstr[0] ""
|
||||
|
@ -92,6 +95,9 @@ msgstr[1] ""
|
|||
msgid "%{text} is available"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{title} changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "(checkout the %{link} for information on how to install it)."
|
||||
msgstr ""
|
||||
|
||||
|
@ -101,6 +107,41 @@ msgstr ""
|
|||
msgid "- show less"
|
||||
msgstr ""
|
||||
|
||||
msgid "1 %{type} addition"
|
||||
msgid_plural "%d %{type} additions"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 %{type} modification"
|
||||
msgid_plural "%d %{type} modifications"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 closed issue"
|
||||
msgid_plural "%d closed issues"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 closed merge request"
|
||||
msgid_plural "%d closed merge requests"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 merged merge request"
|
||||
msgid_plural "%d merged merge requests"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 open issue"
|
||||
msgid_plural "%d open issues"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 open merge request"
|
||||
msgid_plural "%d open merge requests"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "1 pipeline"
|
||||
msgid_plural "%d pipelines"
|
||||
msgstr[0] ""
|
||||
|
@ -136,6 +177,9 @@ msgstr ""
|
|||
msgid "Abuse reports"
|
||||
msgstr ""
|
||||
|
||||
msgid "Accept terms"
|
||||
msgstr ""
|
||||
|
||||
msgid "Access Tokens"
|
||||
msgstr ""
|
||||
|
||||
|
@ -367,6 +411,9 @@ msgstr ""
|
|||
msgid "Assignee"
|
||||
msgstr ""
|
||||
|
||||
msgid "Assignee(s)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Attach a file by drag & drop or %{upload_link}"
|
||||
msgstr ""
|
||||
|
||||
|
@ -669,9 +716,39 @@ msgstr ""
|
|||
msgid "CI/CD configuration"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery."
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Auto DevOps (Beta)"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration."
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Disable Auto DevOps"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Enable Auto DevOps"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific %{ci_file}."
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Instance default (%{state})"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Jobs"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|Learn more about Auto DevOps"
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project."
|
||||
msgstr ""
|
||||
|
||||
msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
|
@ -825,6 +902,9 @@ msgstr ""
|
|||
msgid "CircuitBreakerApiLink|circuitbreaker api"
|
||||
msgstr ""
|
||||
|
||||
msgid "Clear search input"
|
||||
msgstr ""
|
||||
|
||||
msgid "Click any <strong>project name</strong> in the project list below to navigate to the project milestone."
|
||||
msgstr ""
|
||||
|
||||
|
@ -1128,6 +1208,12 @@ msgstr ""
|
|||
msgid "ClusterIntegration|properly configured"
|
||||
msgstr ""
|
||||
|
||||
msgid "Collapse"
|
||||
msgstr ""
|
||||
|
||||
msgid "Collapse sidebar"
|
||||
msgstr ""
|
||||
|
||||
msgid "Comment and resolve discussion"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1411,18 +1497,18 @@ msgstr ""
|
|||
msgid "CreateTokenToCloneLink|create a personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "Creates a new branch from %{branchName}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Creates a new branch from %{branchName} and re-directs to create a new merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cron Timezone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cron syntax"
|
||||
msgstr ""
|
||||
|
||||
msgid "CurrentUser|Profile"
|
||||
msgstr ""
|
||||
|
||||
msgid "CurrentUser|Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "Custom notification events"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1465,6 +1551,9 @@ msgstr ""
|
|||
msgid "December"
|
||||
msgstr ""
|
||||
|
||||
msgid "Decline and sign out"
|
||||
msgstr ""
|
||||
|
||||
msgid "Define a custom pattern with cron syntax"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1563,12 +1652,18 @@ msgstr ""
|
|||
msgid "Directory name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Discard changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Discard draft"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dismiss Cycle Analytics introduction box"
|
||||
msgstr ""
|
||||
|
||||
msgid "Domain"
|
||||
msgstr ""
|
||||
|
||||
msgid "Don't show again"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1734,6 +1829,9 @@ msgstr ""
|
|||
msgid "Error updating todo status."
|
||||
msgstr ""
|
||||
|
||||
msgid "Estimated"
|
||||
msgstr ""
|
||||
|
||||
msgid "EventFilterBy|Filter by all"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1761,6 +1859,12 @@ msgstr ""
|
|||
msgid "Every week (Sundays at 4:00am)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Expand"
|
||||
msgstr ""
|
||||
|
||||
msgid "Expand sidebar"
|
||||
msgstr ""
|
||||
|
||||
msgid "Explore projects"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1797,9 +1901,6 @@ msgstr ""
|
|||
msgid "Fields on this page are now uneditable, you can configure"
|
||||
msgstr ""
|
||||
|
||||
msgid "File name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1901,6 +2002,9 @@ msgstr ""
|
|||
msgid "Got it!"
|
||||
msgstr ""
|
||||
|
||||
msgid "Group ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "GroupSettings|Prevent sharing a project within %{group} with other groups"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2023,6 +2127,9 @@ msgstr ""
|
|||
msgid "Import repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "Include a Terms of Service agreement that all users must accept."
|
||||
msgstr ""
|
||||
|
||||
msgid "Install Runner on Kubernetes"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2199,6 +2306,9 @@ msgstr ""
|
|||
msgid "Loading the GitLab IDE..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Loading..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Lock"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2229,7 +2339,10 @@ msgstr ""
|
|||
msgid "March"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark done"
|
||||
msgid "Mark todo as done"
|
||||
msgstr ""
|
||||
|
||||
msgid "Markdown enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "Maximum git storage failures"
|
||||
|
@ -2244,6 +2357,9 @@ msgstr ""
|
|||
msgid "Members"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merge Request:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merge Requests"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2253,6 +2369,9 @@ msgstr ""
|
|||
msgid "Merge request"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merge requests"
|
||||
msgstr ""
|
||||
|
||||
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2313,6 +2432,9 @@ msgstr ""
|
|||
msgid "Move issue"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Name new label"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2387,6 +2509,9 @@ msgstr ""
|
|||
msgid "No file chosen"
|
||||
msgstr ""
|
||||
|
||||
msgid "No files found."
|
||||
msgstr ""
|
||||
|
||||
msgid "No labels created yet."
|
||||
msgstr ""
|
||||
|
||||
|
@ -2675,12 +2800,27 @@ msgstr ""
|
|||
msgid "Pipelines|This project is not currently set up to run pipelines."
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Existing branch name, tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Retry pipeline"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Retry pipeline #%{pipelineId}?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Run Pipeline"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Run on"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Run pipeline"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Search branches"
|
||||
msgstr ""
|
||||
|
||||
msgid "Pipeline|Stop pipeline"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2714,6 +2854,9 @@ msgstr ""
|
|||
msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Please accept the Terms of Service before continuing."
|
||||
msgstr ""
|
||||
|
||||
msgid "Please select at least one filter to see results"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2798,6 +2941,9 @@ msgstr ""
|
|||
msgid "Programming languages used in this repository"
|
||||
msgstr ""
|
||||
|
||||
msgid "Progress"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project '%{project_name}' is in the process of being deleted."
|
||||
msgstr ""
|
||||
|
||||
|
@ -3041,6 +3187,9 @@ msgstr ""
|
|||
msgid "Request Access"
|
||||
msgstr ""
|
||||
|
||||
msgid "Require all users to accept Terms of Service when they access GitLab."
|
||||
msgstr ""
|
||||
|
||||
msgid "Reset git storage health information"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3053,6 +3202,9 @@ msgstr ""
|
|||
msgid "Resolve discussion"
|
||||
msgstr ""
|
||||
|
||||
msgid "Retry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Retry this job"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3115,6 +3267,9 @@ msgstr ""
|
|||
msgid "Search branches and tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search files"
|
||||
msgstr ""
|
||||
|
||||
msgid "Search milestones"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3219,6 +3374,9 @@ msgid_plural "Showing %d events"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Sign out"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sign-in restrictions"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3360,6 +3518,18 @@ msgstr ""
|
|||
msgid "Specify the following URL during the Runner setup:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stage all"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stage changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Staged"
|
||||
msgstr ""
|
||||
|
||||
msgid "Staged %{type}"
|
||||
msgstr ""
|
||||
|
||||
msgid "StarProject|Star"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3410,6 +3580,9 @@ msgstr[1] ""
|
|||
msgid "Tags"
|
||||
msgstr ""
|
||||
|
||||
msgid "Tags:"
|
||||
msgstr ""
|
||||
|
||||
msgid "TagsPage|Browse commits"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3488,6 +3661,12 @@ msgstr ""
|
|||
msgid "Team"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terms of Service"
|
||||
msgstr ""
|
||||
|
||||
msgid "Terms of Service Agreement"
|
||||
msgstr ""
|
||||
|
||||
msgid "The Issue Tracker is the place to add things that need to be improved or solved in a project"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3665,6 +3844,12 @@ msgstr ""
|
|||
msgid "Time between merge request creation and merge/close"
|
||||
msgstr ""
|
||||
|
||||
msgid "Time remaining"
|
||||
msgstr ""
|
||||
|
||||
msgid "Time spent"
|
||||
msgstr ""
|
||||
|
||||
msgid "Time tracking"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3837,6 +4022,9 @@ msgstr ""
|
|||
msgid "Todo"
|
||||
msgstr ""
|
||||
|
||||
msgid "Toggle Sidebar"
|
||||
msgstr ""
|
||||
|
||||
msgid "Toggle sidebar"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3861,6 +4049,12 @@ msgstr ""
|
|||
msgid "Trigger this manual action"
|
||||
msgstr ""
|
||||
|
||||
msgid "Try again"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to load the diff. %{button_try_again}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unlock"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3870,6 +4064,21 @@ msgstr ""
|
|||
msgid "Unresolve discussion"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstage all"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstage changes"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstaged"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstaged %{type}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstaged and staged %{type}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Unstar"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3978,6 +4187,9 @@ msgstr ""
|
|||
msgid "Web terminal"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, users cannot use GitLab until the terms have been accepted."
|
||||
msgstr ""
|
||||
|
||||
msgid "Wiki"
|
||||
msgstr ""
|
||||
|
||||
|
@ -4200,6 +4412,9 @@ msgstr ""
|
|||
msgid "Your projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "ago"
|
||||
msgstr ""
|
||||
|
||||
msgid "among other things"
|
||||
msgstr ""
|
||||
|
||||
|
@ -4223,6 +4438,12 @@ msgstr[1] ""
|
|||
msgid "deploy token"
|
||||
msgstr ""
|
||||
|
||||
msgid "disabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "enabled"
|
||||
msgstr ""
|
||||
|
||||
msgid "estimateCommand|%{slash_command} will update the estimated time with the latest command."
|
||||
msgstr ""
|
||||
|
||||
|
@ -4422,6 +4643,9 @@ msgstr ""
|
|||
msgid "personal access token"
|
||||
msgstr ""
|
||||
|
||||
msgid "remaining"
|
||||
msgstr ""
|
||||
|
||||
msgid "remove due date"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe ApplicationController do
|
||||
include TermsHelper
|
||||
|
||||
let(:user) { create(:user) }
|
||||
|
||||
describe '#check_password_expiration' do
|
||||
|
@ -406,4 +408,65 @@ describe ApplicationController do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'terms' do
|
||||
controller(described_class) do
|
||||
def index
|
||||
render text: 'authenticated'
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
sign_in user
|
||||
end
|
||||
|
||||
it 'does not query more when terms are enforced' do
|
||||
control = ActiveRecord::QueryRecorder.new { get :index }
|
||||
|
||||
enforce_terms
|
||||
|
||||
expect { get :index }.not_to exceed_query_limit(control)
|
||||
end
|
||||
|
||||
context 'when terms are enforced' do
|
||||
before do
|
||||
enforce_terms
|
||||
end
|
||||
|
||||
it 'redirects if the user did not accept the terms' do
|
||||
get :index
|
||||
|
||||
expect(response).to have_gitlab_http_status(302)
|
||||
end
|
||||
|
||||
it 'does not redirect when the user accepted terms' do
|
||||
accept_terms(user)
|
||||
|
||||
get :index
|
||||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
|
||||
context 'for sessionless users' do
|
||||
before do
|
||||
sign_out user
|
||||
end
|
||||
|
||||
it 'renders a 403 when the sessionless user did not accept the terms' do
|
||||
get :index, rss_token: user.rss_token, format: :atom
|
||||
|
||||
expect(response).to have_gitlab_http_status(403)
|
||||
end
|
||||
|
||||
it 'renders a 200 when the sessionless user accepted the terms' do
|
||||
accept_terms(user)
|
||||
|
||||
get :index, rss_token: user.rss_token, format: :atom
|
||||
|
||||
expect(response).to have_gitlab_http_status(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
66
spec/controllers/concerns/internal_redirect_spec.rb
Normal file
66
spec/controllers/concerns/internal_redirect_spec.rb
Normal file
|
@ -0,0 +1,66 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe InternalRedirect do
|
||||
let(:controller_class) do
|
||||
Class.new do
|
||||
include InternalRedirect
|
||||
|
||||
def request
|
||||
@request ||= Struct.new(:host, :port).new('test.host', 80)
|
||||
end
|
||||
end
|
||||
end
|
||||
subject(:controller) { controller_class.new }
|
||||
|
||||
describe '#safe_redirect_path' do
|
||||
it 'is `nil` for invalid uris' do
|
||||
expect(controller.safe_redirect_path('Hello world')).to be_nil
|
||||
end
|
||||
|
||||
it 'is `nil` for paths trying to include a host' do
|
||||
expect(controller.safe_redirect_path('//example.com/hello/world')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns the path if it is valid' do
|
||||
expect(controller.safe_redirect_path('/hello/world')).to eq('/hello/world')
|
||||
end
|
||||
|
||||
it 'returns the path with querystring if it is valid' do
|
||||
expect(controller.safe_redirect_path('/hello/world?hello=world#L123'))
|
||||
.to eq('/hello/world?hello=world#L123')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#safe_redirect_path_for_url' do
|
||||
it 'is `nil` for invalid urls' do
|
||||
expect(controller.safe_redirect_path_for_url('Hello world')).to be_nil
|
||||
end
|
||||
|
||||
it 'is `nil` for urls from a with a different host' do
|
||||
expect(controller.safe_redirect_path_for_url('http://example.com/hello/world')).to be_nil
|
||||
end
|
||||
|
||||
it 'is `nil` for urls from a with a different port' do
|
||||
expect(controller.safe_redirect_path_for_url('http://test.host:3000/hello/world')).to be_nil
|
||||
end
|
||||
|
||||
it 'returns the path if the url is on the same host' do
|
||||
expect(controller.safe_redirect_path_for_url('http://test.host/hello/world')).to eq('/hello/world')
|
||||
end
|
||||
|
||||
it 'returns the path including querystring if the url is on the same host' do
|
||||
expect(controller.safe_redirect_path_for_url('http://test.host/hello/world?hello=world#L123'))
|
||||
.to eq('/hello/world?hello=world#L123')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#host_allowed?' do
|
||||
it 'allows uris with the same host and port' do
|
||||
expect(controller.host_allowed?(URI('http://test.host/test'))).to be(true)
|
||||
end
|
||||
|
||||
it 'rejects uris with other host and port' do
|
||||
expect(controller.host_allowed?(URI('http://example.com/test'))).to be(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -36,6 +36,30 @@ describe Users::TermsController do
|
|||
|
||||
expect(response).to redirect_to(groups_path)
|
||||
end
|
||||
|
||||
it 'redirects to the referer when no redirect specified' do
|
||||
request.env["HTTP_REFERER"] = groups_url
|
||||
|
||||
post :accept, id: term.id
|
||||
|
||||
expect(response).to redirect_to(groups_path)
|
||||
end
|
||||
|
||||
context 'redirecting to another domain' do
|
||||
it 'is prevented when passing a redirect param' do
|
||||
post :accept, id: term.id, redirect: '//example.com/random/path'
|
||||
|
||||
expect(response).to redirect_to(root_path)
|
||||
end
|
||||
|
||||
it 'is prevented when redirecting to the referer' do
|
||||
request.env["HTTP_REFERER"] = 'http://example.com/and/a/path'
|
||||
|
||||
post :accept, id: term.id
|
||||
|
||||
expect(response).to redirect_to(root_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #decline' do
|
||||
|
|
|
@ -2,10 +2,13 @@ require 'spec_helper'
|
|||
|
||||
feature 'Admin updates settings' do
|
||||
include StubENV
|
||||
include TermsHelper
|
||||
|
||||
let(:admin) { create(:admin) }
|
||||
|
||||
before do
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
sign_in(create(:admin))
|
||||
sign_in(admin)
|
||||
visit admin_application_settings_path
|
||||
end
|
||||
|
||||
|
@ -86,6 +89,10 @@ feature 'Admin updates settings' do
|
|||
end
|
||||
|
||||
scenario 'Terms of Service' do
|
||||
# Already have the admin accept terms, so they don't need to accept in this spec.
|
||||
_existing_terms = create(:term)
|
||||
accept_terms(admin)
|
||||
|
||||
page.within('.as-terms') do
|
||||
check 'Require all users to accept Terms of Service when they access GitLab.'
|
||||
fill_in 'Terms of Service Agreement', with: 'Be nice!'
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Login' do
|
||||
include TermsHelper
|
||||
|
||||
scenario 'Successful user signin invalidates password reset token' do
|
||||
user = create(:user)
|
||||
|
||||
|
@ -399,4 +401,41 @@ feature 'Login' do
|
|||
expect(page).to have_selector('.tab-pane.active', count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when terms are enforced' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
enforce_terms
|
||||
end
|
||||
|
||||
it 'asks to accept the terms on first login' do
|
||||
visit new_user_session_path
|
||||
|
||||
fill_in 'user_login', with: user.email
|
||||
fill_in 'user_password', with: '12345678'
|
||||
|
||||
click_button 'Sign in'
|
||||
|
||||
expect_to_be_on_terms_page
|
||||
|
||||
click_button 'Accept terms'
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
expect(page).not_to have_content('You are already signed in.')
|
||||
end
|
||||
|
||||
it 'does not ask for terms when the user already accepted them' do
|
||||
accept_terms(user)
|
||||
|
||||
visit new_user_session_path
|
||||
|
||||
fill_in 'user_login', with: user.email
|
||||
fill_in 'user_password', with: '12345678'
|
||||
|
||||
click_button 'Sign in'
|
||||
|
||||
expect(current_path).to eq(root_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Signup' do
|
||||
include TermsHelper
|
||||
|
||||
let(:new_user) { build_stubbed(:user) }
|
||||
|
||||
describe 'username validation', :js do
|
||||
|
@ -132,4 +134,27 @@ describe 'Signup' do
|
|||
expect(page.body).not_to match(/#{new_user.password}/)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when terms are enforced' do
|
||||
before do
|
||||
enforce_terms
|
||||
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
|
||||
click_button "Register"
|
||||
|
||||
expect_to_be_on_terms_page
|
||||
|
||||
click_button 'Accept terms'
|
||||
|
||||
expect(current_path).to eq dashboard_projects_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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!') }
|
||||
|
||||
|
@ -36,4 +38,47 @@ describe 'Users > Terms' do
|
|||
expect(user.reload.terms_accepted?).to be(true)
|
||||
end
|
||||
end
|
||||
|
||||
context 'terms were enforced while session is active', :js do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it 'redirects to terms and back to where the user was going' do
|
||||
visit project_path(project)
|
||||
|
||||
enforce_terms
|
||||
|
||||
within('.nav-sidebar') do
|
||||
click_link 'Issues'
|
||||
end
|
||||
|
||||
expect_to_be_on_terms_page
|
||||
|
||||
click_button('Accept terms')
|
||||
|
||||
expect(current_path).to eq(project_issues_path(project))
|
||||
end
|
||||
|
||||
it 'redirects back to the page the user was trying to save' do
|
||||
visit new_project_issue_path(project)
|
||||
|
||||
fill_in :issue_title, with: 'Hello world, a new issue'
|
||||
fill_in :issue_description, with: "We don't want to lose what the user typed"
|
||||
|
||||
enforce_terms
|
||||
|
||||
click_button 'Submit issue'
|
||||
|
||||
expect(current_path).to eq(terms_path)
|
||||
|
||||
click_button('Accept terms')
|
||||
|
||||
expect(current_path).to eq(new_project_issue_path(project))
|
||||
expect(find_field('issue_title').value).to eq('Hello world, a new issue')
|
||||
expect(find_field('issue_description').value).to eq("We don't want to lose what the user typed")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe GlobalPolicy do
|
||||
include TermsHelper
|
||||
|
||||
let(:current_user) { create(:user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
|
|
19
spec/support/helpers/terms_helper.rb
Normal file
19
spec/support/helpers/terms_helper.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module TermsHelper
|
||||
def enforce_terms
|
||||
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
|
||||
settings = Gitlab::CurrentSettings.current_application_settings
|
||||
ApplicationSettings::UpdateService.new(
|
||||
settings, nil, terms: 'These are the terms', enforce_terms: true
|
||||
).execute
|
||||
end
|
||||
|
||||
def accept_terms(user)
|
||||
terms = Gitlab::CurrentSettings.current_application_settings.latest_terms
|
||||
Users::RespondToTermsService.new(user, terms).execute(accepted: true)
|
||||
end
|
||||
|
||||
def expect_to_be_on_terms_page
|
||||
expect(current_path).to eq terms_path
|
||||
expect(page).to have_content('Please accept the Terms of Service before continuing.')
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue