Commit 300898f0 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee-2017-07-14' into 'master'

CE Upstream - Friday (2017-07-14)

See merge request !2435
parents ca559ae6 807e4ad3
...@@ -7,5 +7,8 @@ export default () => { ...@@ -7,5 +7,8 @@ export default () => {
Cookies.set(el.name, el.value, { Cookies.set(el.name, el.value, {
expires: 365 * 10, expires: 365 * 10,
}); });
document.body.scrollTop = 0;
window.location.reload();
}); });
}; };
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
/* global Mousetrap */ /* global Mousetrap */
/* global findFileURL */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import findAndFollowLink from './shortcuts_dashboard_navigation'; import findAndFollowLink from './shortcuts_dashboard_navigation';
...@@ -20,6 +19,7 @@ import findAndFollowLink from './shortcuts_dashboard_navigation'; ...@@ -20,6 +19,7 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
const $globalDropdownMenu = $('.global-dropdown-menu'); const $globalDropdownMenu = $('.global-dropdown-menu');
const $globalDropdownToggle = $('.global-dropdown-toggle'); const $globalDropdownToggle = $('.global-dropdown-toggle');
const findFileURL = document.body.dataset.findFile;
$('.global-dropdown').on('hide.bs.dropdown', () => { $('.global-dropdown').on('hide.bs.dropdown', () => {
$globalDropdownMenu.removeClass('shortcuts'); $globalDropdownMenu.removeClass('shortcuts');
......
...@@ -187,11 +187,12 @@ ...@@ -187,11 +187,12 @@
@include set-invisible; @include set-invisible;
display: block; display: block;
position: absolute; position: absolute;
width: 100%; width: auto;
top: 100%; top: 100%;
left: 0; left: 0;
z-index: 9; z-index: 9;
min-width: 240px; min-width: 240px;
max-width: 500px;
margin-top: 2px; margin-top: 2px;
margin-bottom: 0; margin-bottom: 0;
font-size: 14px; font-size: 14px;
......
...@@ -244,6 +244,10 @@ ...@@ -244,6 +244,10 @@
} }
} }
.block-last {
padding: 16px 0;
}
.trigger-build-variable { .trigger-build-variable {
color: $code-color; color: $code-color;
} }
......
...@@ -114,6 +114,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -114,6 +114,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:html_emails_enabled, :html_emails_enabled,
:koding_enabled, :koding_enabled,
:koding_url, :koding_url,
:password_authentication_enabled,
:plantuml_enabled, :plantuml_enabled,
:plantuml_url, :plantuml_url,
:max_artifacts_size, :max_artifacts_size,
...@@ -136,7 +137,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -136,7 +137,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:require_two_factor_authentication, :require_two_factor_authentication,
:session_expire_delay, :session_expire_delay,
:sign_in_text, :sign_in_text,
:signin_enabled,
:signup_enabled, :signup_enabled,
:sentry_dsn, :sentry_dsn,
:sentry_enabled, :sentry_enabled,
......
...@@ -174,7 +174,7 @@ class ApplicationController < ActionController::Base ...@@ -174,7 +174,7 @@ class ApplicationController < ActionController::Base
end end
def check_password_expiration def check_password_expiration
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user? if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && current_user.allow_password_authentication?
return redirect_to new_profile_password_path return redirect_to new_profile_password_path
end end
end end
......
class PasswordsController < Devise::PasswordsController class PasswordsController < Devise::PasswordsController
include Gitlab::CurrentSettings
before_action :resource_from_email, only: [:create] before_action :resource_from_email, only: [:create]
before_action :prevent_ldap_reset, only: [:create] before_action :check_password_authentication_available, only: [:create]
before_action :throttle_reset, only: [:create] before_action :throttle_reset, only: [:create]
def edit def edit
...@@ -25,7 +27,7 @@ class PasswordsController < Devise::PasswordsController ...@@ -25,7 +27,7 @@ class PasswordsController < Devise::PasswordsController
def update def update
super do |resource| super do |resource|
if resource.valid? && resource.require_password? if resource.valid? && resource.require_password_creation?
resource.update_attribute(:password_automatically_set, false) resource.update_attribute(:password_automatically_set, false)
end end
end end
...@@ -38,11 +40,11 @@ class PasswordsController < Devise::PasswordsController ...@@ -38,11 +40,11 @@ class PasswordsController < Devise::PasswordsController
self.resource = resource_class.find_by_email(email) self.resource = resource_class.find_by_email(email)
end end
def prevent_ldap_reset def check_password_authentication_available
return unless resource && resource.ldap_user? return if current_application_settings.password_authentication_enabled? && (resource.nil? || resource.allow_password_authentication?)
redirect_to after_sending_reset_password_instructions_path_for(resource_name), redirect_to after_sending_reset_password_instructions_path_for(resource_name),
alert: "Cannot reset password for LDAP user." alert: "Password authentication is unavailable."
end end
def throttle_reset def throttle_reset
......
...@@ -77,7 +77,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController ...@@ -77,7 +77,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController
end end
def authorize_change_password! def authorize_change_password!
return render_404 if @user.ldap_user? render_404 unless @user.allow_password_authentication?
end end
def user_params def user_params
......
...@@ -230,7 +230,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -230,7 +230,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue def issue
return @issue if defined?(@issue) return @issue if defined?(@issue)
# The Sortable default scope causes performance issues when used with find_by # The Sortable default scope causes performance issues when used with find_by
@noteable = @issue ||= @project.issues.find_by!(iid: params[:id]) @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take!
return render_404 unless can?(current_user, :read_issue, @issue) return render_404 unless can?(current_user, :read_issue, @issue)
......
...@@ -109,7 +109,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap ...@@ -109,7 +109,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project @target_project = @merge_request.target_project
@source_project = @merge_request.source_project @source_project = @merge_request.source_project
@commits = @merge_request.compare_commits.reverse @commits = @merge_request.commits
@commit = @merge_request.diff_head_commit @commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id)) @note_counts = Note.where(commit_id: @commits.map(&:id))
......
...@@ -69,8 +69,7 @@ class Projects::TriggersController < Projects::ApplicationController ...@@ -69,8 +69,7 @@ class Projects::TriggersController < Projects::ApplicationController
def trigger_params def trigger_params
params.require(:trigger).permit( params.require(:trigger).permit(
:description, :description
trigger_schedule_attributes: [:id, :active, :cron, :cron_timezone, :ref]
) )
end end
end end
...@@ -59,7 +59,7 @@ class SessionsController < Devise::SessionsController ...@@ -59,7 +59,7 @@ class SessionsController < Devise::SessionsController
user = User.admins.last user = User.admins.last
return unless user && user.require_password? return unless user && user.require_password_creation?
Users::UpdateService.new(user).execute do |user| Users::UpdateService.new(user).execute do |user|
@token = user.generate_reset_token @token = user.generate_reset_token
......
module ApplicationSettingsHelper module ApplicationSettingsHelper
delegate :gravatar_enabled?, delegate :gravatar_enabled?,
:signup_enabled?, :signup_enabled?,
:signin_enabled?, :password_authentication_enabled?,
:akismet_enabled?, :akismet_enabled?,
:koding_enabled?, :koding_enabled?,
to: :current_application_settings to: :current_application_settings
......
...@@ -50,12 +50,12 @@ module ButtonHelper ...@@ -50,12 +50,12 @@ module ButtonHelper
def http_clone_button(project, placement = 'right', append_link: true) def http_clone_button(project, placement = 'right', append_link: true)
klass = 'http-selector' klass = 'http-selector'
klass << ' has-tooltip' if current_user.try(:require_password?) || current_user.try(:require_personal_access_token?) klass << ' has-tooltip' if current_user.try(:require_password_creation?) || current_user.try(:require_personal_access_token_creation_for_git_auth?)
protocol = gitlab_config.protocol.upcase protocol = gitlab_config.protocol.upcase
tooltip_title = tooltip_title =
if current_user.try(:require_password?) if current_user.try(:require_password_creation?)
_("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol } _("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol }
else else
_("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol } _("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol }
......
...@@ -214,11 +214,11 @@ module ProjectsHelper ...@@ -214,11 +214,11 @@ module ProjectsHelper
def show_no_password_message? def show_no_password_message?
cookies[:hide_no_password_message].blank? && !current_user.hide_no_password && cookies[:hide_no_password_message].blank? && !current_user.hide_no_password &&
( current_user.require_password? || current_user.require_personal_access_token? ) ( current_user.require_password_creation? || current_user.require_personal_access_token_creation_for_git_auth? )
end end
def link_to_set_password def link_to_set_password
if current_user.require_password? if current_user.require_password_creation?
link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path
else else
link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path
...@@ -551,4 +551,12 @@ module ProjectsHelper ...@@ -551,4 +551,12 @@ module ProjectsHelper
current_application_settings.restricted_visibility_levels || [] current_application_settings.restricted_visibility_levels || []
end end
def find_file_path
return unless @project && !@project.empty_repo?
ref = @ref || @project.repository.root_ref
project_find_file_path(@project, ref)
end
end end
...@@ -250,6 +250,7 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -250,6 +250,7 @@ class ApplicationSetting < ActiveRecord::Base
koding_url: nil, koding_url: nil,
max_artifacts_size: Settings.artifacts['max_size'], max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'], max_attachment_size: Settings.gitlab['max_attachment_size'],
password_authentication_enabled: Settings.gitlab['password_authentication_enabled'],
performance_bar_allowed_group_id: nil, performance_bar_allowed_group_id: nil,
plantuml_enabled: false, plantuml_enabled: false,
plantuml_url: nil, plantuml_url: nil,
...@@ -264,7 +265,6 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -264,7 +265,6 @@ class ApplicationSetting < ActiveRecord::Base
shared_runners_text: nil, shared_runners_text: nil,
sidekiq_throttling_enabled: false, sidekiq_throttling_enabled: false,
sign_in_text: nil, sign_in_text: nil,
signin_enabled: Settings.gitlab['signin_enabled'],
signup_enabled: Settings.gitlab['signup_enabled'], signup_enabled: Settings.gitlab['signup_enabled'],
terminal_max_session_time: 0, terminal_max_session_time: 0,
two_factor_grace_period: 48, two_factor_grace_period: 48,
......
...@@ -5,25 +5,6 @@ ...@@ -5,25 +5,6 @@
module Sortable module Sortable
extend ActiveSupport::Concern extend ActiveSupport::Concern
module DropDefaultScopeOnFinders
# Override these methods to drop the `ORDER BY id DESC` default scope.
# See http://dba.stackexchange.com/a/110919 for why we do this.
%i[find find_by find_by!].each do |meth|
define_method meth do |*args, &block|
return super(*args, &block) if block
unordered_relation = unscope(:order)
# We cannot simply call `meth` on `unscope(:order)`, since that is also
# an instance of the same relation class this module is included into,
# which means we'd get infinite recursion.
# We explicitly use the original implementation to prevent this.
original_impl = method(__method__).super_method.unbind
original_impl.bind(unordered_relation).call(*args)
end
end
end
included do included do
# By default all models should be ordered # By default all models should be ordered
# by created_at field starting from newest # by created_at field starting from newest
...@@ -37,10 +18,6 @@ module Sortable ...@@ -37,10 +18,6 @@ module Sortable
scope :order_updated_asc, -> { reorder(updated_at: :asc) } scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) } scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) } scope :order_name_desc, -> { reorder(name: :desc) }
# All queries (relations) on this model are instances of this `relation_klass`.
relation_klass = relation_delegate_class(ActiveRecord::Relation)
relation_klass.prepend DropDefaultScopeOnFinders
end end
module ClassMethods module ClassMethods
......
...@@ -35,9 +35,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -35,9 +35,6 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing? after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed after_update :reload_diff_if_branch_changed
delegate :commits, :real_size, :commit_shas, :commits_count,
to: :merge_request_diff, prefix: nil
delegate :codeclimate_artifact, to: :head_pipeline, prefix: :head, allow_nil: true delegate :codeclimate_artifact, to: :head_pipeline, prefix: :head, allow_nil: true
delegate :codeclimate_artifact, to: :base_pipeline, prefix: :base, allow_nil: true delegate :codeclimate_artifact, to: :base_pipeline, prefix: :base, allow_nil: true
...@@ -231,6 +228,36 @@ class MergeRequest < ActiveRecord::Base ...@@ -231,6 +228,36 @@ class MergeRequest < ActiveRecord::Base
"#{project.to_reference(from, full: full)}#{reference}" "#{project.to_reference(from, full: full)}#{reference}"
end end
def commits
if persisted?
merge_request_diff.commits
elsif compare_commits
compare_commits.reverse
else
[]
end
end
def commits_count
if persisted?
merge_request_diff.commits_count
elsif compare_commits
compare_commits.size
else
0
end
end
def commit_shas
if persisted?
merge_request_diff.commit_shas
elsif compare_commits
compare_commits.reverse.map(&:sha)
else
[]
end
end
def first_commit def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end end
...@@ -253,9 +280,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -253,9 +280,7 @@ class MergeRequest < ActiveRecord::Base
def diff_size def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform # Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here. # highlighting, which we don't need here.
return real_size if merge_request_diff merge_request_diff&.real_size || diffs.real_size
diffs.real_size
end end
def diff_base_commit def diff_base_commit
......
...@@ -844,7 +844,7 @@ class Project < ActiveRecord::Base ...@@ -844,7 +844,7 @@ class Project < ActiveRecord::Base
end end
def ci_service def ci_service
@ci_service ||= ci_services.find_by(active: true) @ci_service ||= ci_services.reorder(nil).find_by(active: true)
end end
def deployment_services def deployment_services
...@@ -852,7 +852,7 @@ class Project < ActiveRecord::Base ...@@ -852,7 +852,7 @@ class Project < ActiveRecord::Base
end end
def deployment_service def deployment_service
@deployment_service ||= deployment_services.find_by(active: true) @deployment_service ||= deployment_services.reorder(nil).find_by(active: true)
end end
def monitoring_services def monitoring_services
...@@ -860,7 +860,7 @@ class Project < ActiveRecord::Base ...@@ -860,7 +860,7 @@ class Project < ActiveRecord::Base
end end
def monitoring_service def monitoring_service
@monitoring_service ||= monitoring_services.find_by(active: true) @monitoring_service ||= monitoring_services.reorder(nil).find_by(active: true)
end end
def jira_tracker? def jira_tracker?
......
...@@ -130,6 +130,7 @@ class Repository ...@@ -130,6 +130,7 @@ class Repository
commits commits
end end
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/384
def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0) def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0)
unless exists? && has_visible_content? && query.present? unless exists? && has_visible_content? && query.present?
return [] return []
...@@ -617,6 +618,7 @@ class Repository ...@@ -617,6 +618,7 @@ class Repository
commit(sha) commit(sha)
end end
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/383
def last_commit_id_for_path(sha, path) def last_commit_id_for_path(sha, path)
key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}" key = path.blank? ? "last_commit_id_for_path:#{sha}" : "last_commit_id_for_path:#{sha}:#{Digest::SHA1.hexdigest(path)}"
......
...@@ -599,16 +599,20 @@ class User < ActiveRecord::Base ...@@ -599,16 +599,20 @@ class User < ActiveRecord::Base
keys.count == 0 && Gitlab::ProtocolAccess.allowed?('ssh') keys.count == 0 && Gitlab::ProtocolAccess.allowed?('ssh')
end end
def require_password? def require_password_creation?
password_automatically_set? && !ldap_user? && current_application_settings.signin_enabled? password_automatically_set? && allow_password_authentication?
end end
def require_personal_access_token? def require_personal_access_token_creation_for_git_auth?
return false if current_application_settings.signin_enabled? || ldap_user? return false if allow_password_authentication? || ldap_user?
PersonalAccessTokensFinder.new(user: self, impersonation: false, state: 'active').execute.none? PersonalAccessTokensFinder.new(user: self, impersonation: false, state: 'active').execute.none?
end end
def allow_password_authentication?
!ldap_user? && current_application_settings.password_authentication_enabled?
end
def can_change_username? def can_change_username?
gitlab_config.username_changing_enabled gitlab_config.username_changing_enabled
end end
......
...@@ -129,6 +129,7 @@ class GitOperationService ...@@ -129,6 +129,7 @@ class GitOperationService
end end
end end
# Gitaly note: JV: wait with migrating #update_ref until we know how to migrate its call sites.
def update_ref(ref, newrev, oldrev) def update_ref(ref, newrev, oldrev)
# We use 'git update-ref' because libgit2/rugged currently does not # We use 'git update-ref' because libgit2/rugged currently does not
# offer 'compare and swap' ref updates. Without compare-and-swap we can # offer 'compare and swap' ref updates. Without compare-and-swap we can
......
...@@ -165,9 +165,9 @@ ...@@ -165,9 +165,9 @@
.form-group .form-group
.col-sm-offset-2.col-sm-10 .col-sm-offset-2.col-sm-10
.checkbox .checkbox
= f.label :signin_enabled do = f.label :password_authentication_enabled do
= f.check_box :signin_enabled = f.check_box :password_authentication_enabled
Sign-in enabled Password authentication enabled
- if omniauth_enabled? && button_based_providers.any? - if omniauth_enabled? && button_based_providers.any?
.form-group .form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2' = f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'
......
...@@ -6,15 +6,15 @@ ...@@ -6,15 +6,15 @@
- else - else
= render 'devise/shared/tabs_normal' = render 'devise/shared/tabs_normal'
.tab-content .tab-content
- if signin_enabled? || ldap_enabled? || crowd_enabled? - if password_authentication_enabled? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box' = render 'devise/shared/signin_box'
-# Signup only makes sense if you can also sign-in -# Signup only makes sense if you can also sign-in
- if signin_enabled? && signup_enabled? - if password_authentication_enabled? && signup_enabled?
= render 'devise/shared/signup_box' = render 'devise/shared/signup_box'
-# Show a message if none of the mechanisms above are enabled -# Show a message if none of the mechanisms above are enabled
- if !signin_enabled? && !ldap_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?) - if !password_authentication_enabled? && !ldap_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
%div %div
No authentication methods configured. No authentication methods configured.
......
...@@ -13,12 +13,12 @@ ...@@ -13,12 +13,12 @@
.login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) } .login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) }
.login-body .login-body
= render 'devise/sessions/new_ldap', server: server = render 'devise/sessions/new_ldap', server: server
- if signin_enabled? - if password_authentication_enabled?
.login-box.tab-pane{ id: 'ldap-standard', role: 'tabpanel' } .login-box.tab-pane{ id: 'ldap-standard', role: 'tabpanel' }
.login-body .login-body
= render 'devise/sessions/new_base' = render 'devise/sessions/new_base'
- elsif signin_enabled? - elsif password_authentication_enabled?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' } .login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body .login-body
= render 'devise/sessions/new_base' = render 'devise/sessions/new_base'
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
- @ldap_servers.each_with_index do |server, i| - @ldap_servers.each_with_index do |server, i|
%li{ class: active_when(i.zero? && !crowd_enabled?) } %li{ class: active_when(i.zero? && !crowd_enabled?) }
= link_to server['label'], "##{server['provider_name']}", 'data-toggle' => 'tab' = link_to server['label'], "##{server['provider_name']}", 'data-toggle' => 'tab'
- if signin_enabled? - if password_authentication_enabled?
%li %li
= link_to 'Standard', '#ldap-standard', 'data-toggle' => 'tab' = link_to 'Standard', '#ldap-standard', 'data-toggle' => 'tab'
- if signin_enabled? && signup_enabled? - if password_authentication_enabled? && signup_enabled?
%li %li
= link_to 'Register', '#register-pane', 'data-toggle' => 'tab' = link_to 'Register', '#register-pane', 'data-toggle' => 'tab'
%ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' } %ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' } %li.active{ role: 'presentation' }
%a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in %a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
- if signin_enabled? && signup_enabled? - if password_authentication_enabled? && signup_enabled?
%li{ role: 'presentation' } %li{ role: 'presentation' }
%a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register %a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
= icon('bullhorn') = icon('bullhorn')
= license_message = license_message
- BroadcastMessage.current.each do |message| - BroadcastMessage.current&.each do |message|
= broadcast_message(message) = broadcast_message(message)
!!! 5 !!! 5
%html{ lang: I18n.locale, class: "#{page_class}" } %html{ lang: I18n.locale, class: "#{page_class}" }
= render "layouts/head" = render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form = render "layouts/init_auto_complete" if @gfm_form
- if show_new_nav? - if show_new_nav?
= render "layouts/header/new" = render "layouts/header/new"
......
...@@ -103,8 +103,3 @@ ...@@ -103,8 +103,3 @@
= yield :header_content = yield :header_content
= render 'shared/outdated_browser' = render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
- if ref = @ref || @project.repository.root_ref
:javascript
var findFileURL = "#{project_find_file_path(@project, ref)}";
...@@ -84,8 +84,3 @@ ...@@ -84,8 +84,3 @@
= icon('times', class: 'js-navbar-toggle-left', style: 'display: none;') = icon('times', class: 'js-navbar-toggle-left', style: 'display: none;')
= render 'shared/outdated_browser' = render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
- if ref = @ref || @project.repository.root_ref
:javascript
var findFileURL = "#{project_find_file_path(@project, ref)}";
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
= link_to profile_emails_path, title: 'Emails' do = link_to profile_emails_path, title: 'Emails' do
%span %span
Emails Emails
- unless current_user.ldap_user? - if current_user.allow_password_authentication?
= nav_link(controller: :passwords) do = nav_link(controller: :passwords) do
= link_to edit_profile_password_path, title: 'Password' do = link_to edit_profile_password_path, title: 'Password' do
%span %span
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#js-details-block-vue #js-details-block-vue
- if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?) - if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?)
.block{ class: ("block-first" if !@build.coverage) } .block
.title .title
Job artifacts Job artifacts
- if @build.artifacts_expired? - if @build.artifacts_expired?
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
Browse Browse
- if @build.trigger_request - if @build.trigger_request
.build-widget .build-widget.block
%h4.title %h4.title
Trigger Trigger
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
.js-build-variable.trigger-build-variable= key .js-build-variable.trigger-build-variable= key
.js-build-value.trigger-build-value= value .js-build-value.trigger-build-value= value
.block %div{ class: (@build.pipeline.stages_count > 1 ? "block" : "block-last") }
%p %p
Commit Commit
= link_to @build.pipeline.short_sha, project_commit_path(@project, @build.pipeline.sha), class: 'commit-sha link-commit' = link_to @build.pipeline.short_sha, project_commit_path(@project, @build.pipeline.sha), class: 'commit-sha link-commit'
...@@ -69,7 +69,7 @@ ...@@ -69,7 +69,7 @@
- if @build.pipeline.stages_count > 1 - if @build.pipeline.stages_count > 1
.dropdown.build-dropdown .dropdown.build-dropdown
.title %div
%span{ class: "ci-status-icon-#{@build.pipeline.status}" } %span{ class: "ci-status-icon-#{@build.pipeline.status}" }
= ci_icon_for_status(@build.pipeline.status) = ci_icon_for_status(@build.pipeline.status)
Pipeline Pipeline
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
%p %p
Metrics are automatically configured and monitored Metrics are automatically configured and monitored
based on a library of metrics from popular exporters. based on a library of metrics from popular exporters.
= link_to 'More information', '#' = link_to 'More information', help_page_path('user/project/integrations/prometheus')
.col-lg-9 .col-lg-9
.panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } } .panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } }
...@@ -41,5 +41,5 @@ ...@@ -41,5 +41,5 @@
%code %code
$CI_ENVIRONMENT_SLUG $CI_ENVIRONMENT_SLUG
to exporter&rsquo;s queries. to exporter&rsquo;s queries.
= link_to 'More information', '#' = link_to 'More information', help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels')
%ul.list-unstyled.metrics-list.js-missing-var-metrics-list %ul.list-unstyled.metrics-list.js-missing-var-metrics-list
...@@ -39,22 +39,3 @@ ...@@ -39,22 +39,3 @@
- else - else
.settings-message.text-center .settings-message.text-center
This user has no active #{type} Tokens. This user has no active #{type} Tokens.
%hr
%h5 Inactive #{type} Tokens (#{inactive_tokens.length})
- if inactive_tokens.present?
.table-responsive
%table.table.inactive-tokens
%thead
%tr
%th Name
%th Created
%tbody
- inactive_tokens.each do |token|
%tr
%td= token.name
%td= token.created_at.to_date.to_s(:medium)
- else
.settings-message.text-center
This user has no inactive #{type} Tokens.
---
title: Remove Inactive Personal Access Tokens list from Access Tokens page
merge_request: 12866
author:
---
title: Supplement Portuguese Brazil translation of Project Page & Repository Page
merge_request: 12156
author: Huang Tao
---
title: Fix vertical space in job details sidebar
merge_request:
author:
---
title: Increase width of dropdown menus automatically
merge_request: 12809
author: Thomas Wucher
---
title: Improve performance of lookups of issues, merge requests etc by dropping unnecessary ORDER BY clause
merge_request:
author:
---
title: Fixes needed when GitLab sign-in is not enabled
merge_request: 12491
author: Robin Bobbitt
...@@ -257,7 +257,7 @@ rescue ArgumentError # no user configured ...@@ -257,7 +257,7 @@ rescue ArgumentError # no user configured
end end
Settings.gitlab['time_zone'] ||= nil Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil? Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil?
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil? Settings.gitlab['password_authentication_enabled'] ||= true if Settings.gitlab['password_authentication_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], []) Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil? Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil?
......
...@@ -196,6 +196,10 @@ if Gitlab::Metrics.enabled? ...@@ -196,6 +196,10 @@ if Gitlab::Metrics.enabled?
loc && loc[0].start_with?(models) && method.source =~ regex loc && loc[0].start_with?(models) && method.source =~ regex
end end
end end
# Ability is in app/models, is not an ActiveRecord model, but should still
# be instrumented.
Gitlab::Metrics::Instrumentation.instrument_methods(Ability)
end end
Gitlab::Metrics::Instrumentation.configure do |config| Gitlab::Metrics::Instrumentation.configure do |config|
......
class RenameApplicationSettingsSigninEnabledToPasswordAuthenticationEnabled < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
rename_column_concurrently :application_settings, :signin_enabled, :password_authentication_enabled
end
def down
cleanup_concurrent_column_rename :application_settings, :password_authentication_enabled, :signin_enabled
end
end
class CleanupApplicationSettingsSigninEnabledRename < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
cleanup_concurrent_column_rename :application_settings, :signin_enabled, :password_authentication_enabled
end
def down
rename_column_concurrently :application_settings, :password_authentication_enabled, :signin_enabled
end
end
...@@ -42,7 +42,6 @@ ActiveRecord::Schema.define(version: 20170707184244) do ...@@ -42,7 +42,6 @@ ActiveRecord::Schema.define(version: 20170707184244) do
create_table "application_settings", force: :cascade do |t| create_table "application_settings", force: :cascade do |t|
t.integer "default_projects_limit" t.integer "default_projects_limit"
t.boolean "signup_enabled" t.boolean "signup_enabled"
t.boolean "signin_enabled"
t.boolean "gravatar_enabled" t.boolean "gravatar_enabled"
t.text "sign_in_text" t.text "sign_in_text"
t.datetime "created_at" t.datetime "created_at"
...@@ -149,6 +148,7 @@ ActiveRecord::Schema.define(version: 20170707184244) do ...@@ -149,6 +148,7 @@ ActiveRecord::Schema.define(version: 20170707184244) do
t.string "slack_app_secret" t.string "slack_app_secret"
t.string "slack_app_verification_token" t.string "slack_app_verification_token"
t.integer "performance_bar_allowed_group_id" t.integer "performance_bar_allowed_group_id"
t.boolean "password_authentication_enabled"
end end
create_table "approvals", force: :cascade do |t| create_table "approvals", force: :cascade do |t|
......
...@@ -25,7 +25,7 @@ Example response: ...@@ -25,7 +25,7 @@ Example response:
"id" : 1, "id" : 1,
"default_branch_protection" : 2, "default_branch_protection" : 2,
"restricted_visibility_levels" : [], "restricted_visibility_levels" : [],
"signin_enabled" : true, "password_authentication_enabled" : true,
"after_sign_out_path" : null, "after_sign_out_path" : null,
"max_attachment_size" : 10, "max_attachment_size" : 10,
"user_oauth_applications" : true, "user_oauth_applications" : true,
...@@ -62,7 +62,7 @@ PUT /application/settings ...@@ -62,7 +62,7 @@ PUT /application/settings
| --------- | ---- | :------: | ----------- | | --------- | ---- | :------: | ----------- |
| `default_projects_limit` | integer | no | Project limit per user. Default is `100000` | | `default_projects_limit` | integer | no | Project limit per user. Default is `100000` |
| `signup_enabled` | boolean | no | Enable registration. Default is `true`. | | `signup_enabled` | boolean | no | Enable registration. Default is `true`. |
| `signin_enabled` | boolean | no | Enable login via a GitLab account. Default is `true`. | | `password_authentication_enabled` | boolean | no | Enable authentication via a GitLab account password. Default is `true`. |
| `gravatar_enabled` | boolean | no | Enable Gravatar | | `gravatar_enabled` | boolean | no | Enable Gravatar |
| `sign_in_text` | string | no | Text on login page | | `sign_in_text` | string | no | Text on login page |
| `home_page_url` | string | no | Redirect to this URL when not logged in | | `home_page_url` | string | no | Redirect to this URL when not logged in |
...@@ -110,7 +110,7 @@ Example response: ...@@ -110,7 +110,7 @@ Example response:
"id": 1, "id": 1,
"default_projects_limit": 100000, "default_projects_limit": 100000,
"signup_enabled": true, "signup_enabled": true,
"signin_enabled": true, "password_authentication_enabled": true,
"gravatar_enabled": true, "gravatar_enabled": true,
"sign_in_text": "", "sign_in_text": "",
"created_at": "2015-06-12T15:51:55.432Z", "created_at": "2015-06-12T15:51:55.432Z",
......
# InputSetter # InputSetter
`InputSetter` is a plugin that allows for udating DOM out of the scope of droplab when a list item is clicked. `InputSetter` is a plugin that allows for updating DOM out of the scope of droplab when a list item is clicked.
## Usage ## Usage
......
...@@ -12,6 +12,56 @@ The `setup` task is a alias for `gitlab:setup`. ...@@ -12,6 +12,56 @@ The `setup` task is a alias for `gitlab:setup`.
This tasks calls `db:reset` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and finally it calls `db:seed_fu` to seed the database. This tasks calls `db:reset` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and finally it calls `db:seed_fu` to seed the database.
Note: `db:setup` calls `db:seed` but this does nothing. Note: `db:setup` calls `db:seed` but this does nothing.
### Automation
If you're very sure that you want to **wipe the current database** and refill
seeds, you could:
``` shell
echo 'yes' | bundle exec rake setup
```
To save you from answering `yes` manually.
### Discard stdout
Since the script would print a lot of information, it could be slowing down
your terminal, and it would generate more than 20G logs if you just redirect
it to a file. If we don't care about the output, we could just redirect it to
`/dev/null`:
``` shell
echo 'yes' | bundle exec rake setup > /dev/null
```
Note that since you can't see the questions from stdout, you might just want
to `echo 'yes'` to keep it running. It would still print the errors on stderr
so no worries about missing errors.
### Notes for MySQL
Since the seeds would contain various UTF-8 characters, such as emojis or so,
we'll need to make sure that we're using `utf8mb4` for all the encoding
settings and `utf8mb4_unicode_ci` for collation. Please check
[MySQL utf8mb4 support](../install/database_mysql.md#mysql-utf8mb4-support)
Make sure that `config/database.yml` has `encoding: utf8mb4`, too.
Next, we'll need to update the schema to make the indices fit:
``` shell
sed -i 's/limit: 255/limit: 191/g' db/schema.rb
```
Then run the setup script:
``` shell
bundle exec rake setup
```
To make sure that indices still fit. You could find great details in:
[How to support full Unicode in MySQL databases](https://mathiasbynens.be/notes/mysql-utf8mb4)
## Run tests ## Run tests
In order to run the test you can use the following commands: In order to run the test you can use the following commands:
......
...@@ -695,7 +695,8 @@ module API ...@@ -695,7 +695,8 @@ module API
expose :id expose :id
expose :default_projects_limit expose :default_projects_limit
expose :signup_enabled expose :signup_enabled
expose :signin_enabled expose :password_authentication_enabled
expose :password_authentication_enabled, as: :signin_enabled
expose :gravatar_enabled expose :gravatar_enabled
expose :sign_in_text expose :sign_in_text
expose :after_sign_up_text expose :after_sign_up_text
......
...@@ -113,7 +113,7 @@ module API ...@@ -113,7 +113,7 @@ module API
end end
get "/broadcast_message" do get "/broadcast_message" do
if message = BroadcastMessage.current.last if message = BroadcastMessage.current&.last
present message, with: Entities::BroadcastMessage present message, with: Entities::BroadcastMessage
else else
{} {}
......
...@@ -65,6 +65,7 @@ module API ...@@ -65,6 +65,7 @@ module API
:shared_runners_enabled, :shared_runners_enabled,
:sidekiq_throttling_enabled, :sidekiq_throttling_enabled,
:sign_in_text, :sign_in_text,
:password_authentication_enabled,
:signin_enabled, :signin_enabled,
:signup_enabled, :signup_enabled,
:terminal_max_session_time, :terminal_max_session_time,
...@@ -95,7 +96,9 @@ module API ...@@ -95,7 +96,9 @@ module API
requires :domain_blacklist, type: String, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com' requires :domain_blacklist, type: String, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
end end
optional :after_sign_up_text, type: String, desc: 'Text shown after sign up' optional :after_sign_up_text, type: String, desc: 'Text shown after sign up'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if sign in is enabled' optional :password_authentication_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled'
mutually_exclusive :password_authentication_enabled, :signin_enabled
optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to setup Two-factor authentication' optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to setup Two-factor authentication'
given require_two_factor_authentication: ->(val) { val } do given require_two_factor_authentication: ->(val) { val } do
requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication' requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication'
...@@ -216,6 +219,10 @@ module API ...@@ -216,6 +219,10 @@ module API
put "application/settings" do put "application/settings" do
attrs = declared_params(include_missing: false) attrs = declared_params(include_missing: false)
if attrs.has_key?(:signin_enabled)
attrs[:password_authentication_enabled] = attrs.delete(:signin_enabled)
end
if current_settings.update_attributes(attrs) if current_settings.update_attributes(attrs)
present current_settings, with: Entities::ApplicationSetting present current_settings, with: Entities::ApplicationSetting
else else
......
...@@ -46,39 +46,6 @@ module API ...@@ -46,39 +46,6 @@ module API
expose :awardable_id, :awardable_type expose :awardable_id, :awardable_type
end end
class ApplicationSetting < Grape::Entity
expose :id
expose :default_projects_limit
expose :signup_enabled
expose :signin_enabled
expose :gravatar_enabled
expose :sign_in_text
expose :after_sign_up_text
expose :created_at
expose :updated_at
expose :home_page_url
expose :default_branch_protection
expose :restricted_visibility_levels
expose :max_attachment_size
expose :session_expire_delay
expose :default_project_visibility
expose :default_snippet_visibility
expose :default_group_visibility
expose :domain_whitelist
expose :domain_blacklist_enabled
expose :domain_blacklist
expose :user_oauth_applications
expose :after_sign_out_path
expose :container_registry_token_expire_delay
expose :repository_storage
expose :repository_storages
expose :koding_enabled
expose :koding_url
expose :plantuml_enabled
expose :plantuml_url
expose :terminal_max_session_time
end
class Project < Grape::Entity class Project < Grape::Entity
expose :id, :description, :default_branch, :tag_list expose :id, :description, :default_branch, :tag_list
expose :public?, as: :public expose :public?, as: :public
...@@ -209,7 +176,8 @@ module API ...@@ -209,7 +176,8 @@ module API
expose :id expose :id
expose :default_projects_limit expose :default_projects_limit
expose :signup_enabled expose :signup_enabled
expose :signin_enabled expose :password_authentication_enabled
expose :password_authentication_enabled, as: :signin_enabled
expose :gravatar_enabled expose :gravatar_enabled
expose :sign_in_text expose :sign_in_text
expose :after_sign_up_text expose :after_sign_up_text
......
...@@ -44,7 +44,9 @@ module API ...@@ -44,7 +44,9 @@ module API
requires :domain_blacklist, type: String, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com' requires :domain_blacklist, type: String, desc: 'Users with e-mail addresses that match these domain(s) will NOT be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com'
end end
optional :after_sign_up_text, type: String, desc: 'Text shown after sign up' optional :after_sign_up_text, type: String, desc: 'Text shown after sign up'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if sign in is enabled' optional :password_authentication_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled'
mutually_exclusive :password_authentication_enabled, :signin_enabled
optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to setup Two-factor authentication' optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to setup Two-factor authentication'
given require_two_factor_authentication: ->(val) { val } do given require_two_factor_authentication: ->(val) { val } do
requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication' requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication'
...@@ -127,7 +129,7 @@ module API ...@@ -127,7 +129,7 @@ module API
:max_attachment_size, :session_expire_delay, :disabled_oauth_sign_in_sources, :max_attachment_size, :session_expire_delay, :disabled_oauth_sign_in_sources,
:user_oauth_applications, :user_default_external, :signup_enabled, :user_oauth_applications, :user_default_external, :signup_enabled,
:send_user_confirmation_email, :domain_whitelist, :domain_blacklist_enabled, :send_user_confirmation_email, :domain_whitelist, :domain_blacklist_enabled,
:after_sign_up_text, :signin_enabled, :require_two_factor_authentication, :after_sign_up_text, :password_authentication_enabled, :signin_enabled, :require_two_factor_authentication,
:home_page_url, :after_sign_out_path, :sign_in_text, :help_page_text, :home_page_url, :after_sign_out_path, :sign_in_text, :help_page_text,
:shared_runners_enabled, :max_artifacts_size, :max_pages_size, :container_registry_token_expire_delay, :shared_runners_enabled, :max_artifacts_size, :max_pages_size, :container_registry_token_expire_delay,
:metrics_enabled, :sidekiq_throttling_enabled, :recaptcha_enabled, :metrics_enabled, :sidekiq_throttling_enabled, :recaptcha_enabled,
...@@ -139,7 +141,13 @@ module API ...@@ -139,7 +141,13 @@ module API
:repository_storage, :repository_storages, :repository_size_limit :repository_storage, :repository_storages, :repository_size_limit
end end
put "application/settings" do put "application/settings" do
if current_settings.update_attributes(declared_params(include_missing: false)) attrs = declared_params(include_missing: false)
if attrs.has_key?(:signin_enabled)
attrs[:password_authentication_enabled] = attrs.delete(:signin_enabled)
end
if current_settings.update_attributes(attrs)
present current_settings, with: Entities::ApplicationSetting present current_settings, with: Entities::ApplicationSetting
else else
render_validation_error!(current_settings) render_validation_error!(current_settings)
......
...@@ -39,7 +39,7 @@ module Gitlab ...@@ -39,7 +39,7 @@ module Gitlab
rate_limit!(ip, success: result.success?, login: login) rate_limit!(ip, success: result.success?, login: login)
Gitlab::Auth::UniqueIpsLimiter.limit_user!(result.actor) Gitlab::Auth::UniqueIpsLimiter.limit_user!(result.actor)
return result if result.success? || current_application_settings.signin_enabled? || Gitlab::LDAP::Config.enabled? return result if result.success? || current_application_settings.password_authentication_enabled? || Gitlab::LDAP::Config.enabled?
# If sign-in is disabled and LDAP is not configured, recommend a # If sign-in is disabled and LDAP is not configured, recommend a
# personal access token on failed auth attempts # personal access token on failed auth attempts
...@@ -50,6 +50,10 @@ module Gitlab ...@@ -50,6 +50,10 @@ module Gitlab
# Avoid resource intensive login checks if password is not provided # Avoid resource intensive login checks if password is not provided
return unless password.present? return unless password.present?
# Nothing to do here if internal auth is disabled and LDAP is
# not configured
return unless current_application_settings.password_authentication_enabled? || Gitlab::LDAP::Config.enabled?
Gitlab::Auth::UniqueIpsLimiter.limit_user! do Gitlab::Auth::UniqueIpsLimiter.limit_user! do
user = User.by_login(login) user = User.by_login(login)
......
...@@ -38,7 +38,7 @@ module Gitlab ...@@ -38,7 +38,7 @@ module Gitlab
repo = options.delete(:repo) repo = options.delete(:repo)
raise 'Gitlab::Git::Repository is required' unless repo.respond_to?(:log) raise 'Gitlab::Git::Repository is required' unless repo.respond_to?(:log)
repo.log(options).map { |c| decorate(c) } repo.log(options)
end end
# Get single commit # Get single commit
......
...@@ -331,85 +331,10 @@ module Gitlab ...@@ -331,85 +331,10 @@ module Gitlab
# ) # )
# #
def log(options) def log(options)
default_options = { raw_log(options).map { |c| Commit.decorate(c) }
limit: 10,
offset: 0,
path: nil,
follow: false,
skip_merges: false,
disable_walk: false,
after: nil,
before: nil
}
options = default_options.merge(options)
options[:limit] ||= 0
options[:offset] ||= 0
actual_ref = options[:ref] || root_ref
begin
sha = sha_from_ref(actual_ref)
rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError
# Return an empty array if the ref wasn't found
return []
end
if log_using_shell?(options)
log_by_shell(sha, options)
else
log_by_walk(sha, options)
end
end
def log_using_shell?(options)
options[:path].present? ||
options[:disable_walk] ||
options[:skip_merges] ||
options[:after] ||
options[:before]
end
def log_by_walk(sha, options)
walk_options = {
show: sha,
sort: Rugged::SORT_NONE,
limit: options[:limit],
offset: options[:offset]
}
Rugged::Walker.walk(rugged, walk_options).to_a
end
def log_by_shell(sha, options)
limit = options[:limit].to_i
offset = options[:offset].to_i
use_follow_flag = options[:follow] && options[:path].present?
# We will perform the offset in Ruby because --follow doesn't play well with --skip.
# See: https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
offset_in_ruby = use_follow_flag && options[:offset].present?
limit += offset if offset_in_ruby
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} log]
cmd << "--max-count=#{limit}"
cmd << '--format=%H'
cmd << "--skip=#{offset}" unless offset_in_ruby
cmd << '--follow' if use_follow_flag
cmd << '--no-merges' if options[:skip_merges]
cmd << "--after=#{options[:after].iso8601}" if options[:after]
cmd << "--before=#{options[:before].iso8601}" if options[:before]
cmd << sha
# :path can be a string or an array of strings
if options[:path].present?
cmd << '--'
cmd += Array(options[:path])
end
raw_output = IO.popen(cmd) { |io| io.read }
lines = offset_in_ruby ? raw_output.lines.drop(offset) : raw_output.lines
lines.map! { |c| Rugged::Commit.new(rugged, c.strip) }
end end
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/382
def count_commits(options) def count_commits(options)
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list] cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list]
cmd << "--after=#{options[:after].iso8601}" if options[:after] cmd << "--after=#{options[:after].iso8601}" if options[:after]
...@@ -454,7 +379,7 @@ module Gitlab ...@@ -454,7 +379,7 @@ module Gitlab
# Counts the amount of commits between `from` and `to`. # Counts the amount of commits between `from` and `to`.
def count_commits_between(from, to) def count_commits_between(from, to)
commits_between(from, to).size Commit.between(self, from, to).size
end end
# Returns the SHA of the most recent common ancestor of +from+ and +to+ # Returns the SHA of the most recent common ancestor of +from+ and +to+
...@@ -912,6 +837,89 @@ module Gitlab ...@@ -912,6 +837,89 @@ module Gitlab
private private
def raw_log(options)
default_options = {
limit: 10,
offset: 0,
path: nil,
follow: false,
skip_merges: false,
disable_walk: false,
after: nil,
before: nil
}
options = default_options.merge(options)
options[:limit] ||= 0
options[:offset] ||= 0
actual_ref = options[:ref] || root_ref
begin
sha = sha_from_ref(actual_ref)
rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError
# Return an empty array if the ref wasn't found
return []
end
if log_using_shell?(options)
log_by_shell(sha, options)
else
log_by_walk(sha, options)
end
end
def log_using_shell?(options)
options[:path].present? ||
options[:disable_walk] ||
options[:skip_merges] ||
options[:after] ||
options[:before]
end
def log_by_walk(sha, options)
walk_options = {
show: sha,
sort: Rugged::SORT_NONE,
limit: options[:limit],
offset: options[:offset]
}
Rugged::Walker.walk(rugged, walk_options).to_a
end
# Gitaly note: JV: although #log_by_shell shells out to Git I think the
# complexity is such that we should migrate it as Ruby before trying to
# do it in Go.
def log_by_shell(sha, options)
limit = options[:limit].to_i
offset = options[:offset].to_i
use_follow_flag = options[:follow] && options[:path].present?
# We will perform the offset in Ruby because --follow doesn't play well with --skip.
# See: https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
offset_in_ruby = use_follow_flag && options[:offset].present?
limit += offset if offset_in_ruby
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} log]
cmd << "--max-count=#{limit}"
cmd << '--format=%H'
cmd << "--skip=#{offset}" unless offset_in_ruby
cmd << '--follow' if use_follow_flag
cmd << '--no-merges' if options[:skip_merges]
cmd << "--after=#{options[:after].iso8601}" if options[:after]
cmd << "--before=#{options[:before].iso8601}" if options[:before]
cmd << sha
# :path can be a string or an array of strings
if options[:path].present?
cmd << '--'
cmd += Array(options[:path])
end
raw_output = IO.popen(cmd) { |io| io.read }
lines = offset_in_ruby ? raw_output.lines.drop(offset) : raw_output.lines
lines.map! { |c| Rugged::Commit.new(rugged, c.strip) }
end
# We are trying to deprecate this method because it does a lot of work # We are trying to deprecate this method because it does a lot of work
# but it seems to be used only to look up submodule URL's. # but it seems to be used only to look up submodule URL's.
# https://gitlab.com/gitlab-org/gitaly/issues/329 # https://gitlab.com/gitlab-org/gitaly/issues/329
......
# Gitaly note: JV: does not need to be migrated, works without a repo.
module Gitlab module Gitlab
module GitRefValidator module GitRefValidator
extend self extend self
......
# Gitaly note: JV: two sets of straightforward RPC's. 1 Hard RPC: fork_repository.
# SSH key operations are not part of Gitaly so will never be migrated.
require 'securerandom' require 'securerandom'
module Gitlab module Gitlab
...@@ -68,6 +71,7 @@ module Gitlab ...@@ -68,6 +71,7 @@ module Gitlab
# Ex. # Ex.
# add_repository("/path/to/storage", "gitlab/gitlab-ci") # add_repository("/path/to/storage", "gitlab/gitlab-ci")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def add_repository(storage, name) def add_repository(storage, name)
gitlab_shell_fast_execute([gitlab_shell_projects_path, gitlab_shell_fast_execute([gitlab_shell_projects_path,
'add-project', storage, "#{name}.git"]) 'add-project', storage, "#{name}.git"])
...@@ -81,6 +85,7 @@ module Gitlab ...@@ -81,6 +85,7 @@ module Gitlab
# Ex. # Ex.
# import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://github.com/randx/six.git") # import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://github.com/randx/six.git")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def import_repository(storage, name, url) def import_repository(storage, name, url)
# Timeout should be less than 900 ideally, to prevent the memory killer # Timeout should be less than 900 ideally, to prevent the memory killer
# to silently kill the process without knowing we are timing out here. # to silently kill the process without knowing we are timing out here.
...@@ -127,6 +132,7 @@ module Gitlab ...@@ -127,6 +132,7 @@ module Gitlab
# Ex. # Ex.
# fetch_remote("gitlab/gitlab-ci", "upstream") # fetch_remote("gitlab/gitlab-ci", "upstream")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def fetch_remote(storage, name, remote, forced: false, no_tags: false) def fetch_remote(storage, name, remote, forced: false, no_tags: false)
args = [gitlab_shell_projects_path, 'fetch-remote', storage, "#{name}.git", remote, "#{Gitlab.config.gitlab_shell.git_timeout}"] args = [gitlab_shell_projects_path, 'fetch-remote', storage, "#{name}.git", remote, "#{Gitlab.config.gitlab_shell.git_timeout}"]
args << '--force' if forced args << '--force' if forced
...@@ -143,6 +149,7 @@ module Gitlab ...@@ -143,6 +149,7 @@ module Gitlab
# Ex. # Ex.
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new") # mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def mv_repository(storage, path, new_path) def mv_repository(storage, path, new_path)
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'mv-project', gitlab_shell_fast_execute([gitlab_shell_projects_path, 'mv-project',
storage, "#{path}.git", "#{new_path}.git"]) storage, "#{path}.git", "#{new_path}.git"])
...@@ -171,6 +178,7 @@ module Gitlab ...@@ -171,6 +178,7 @@ module Gitlab
# Ex. # Ex.
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx") # fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "randx")
# #
# Gitaly note: JV: not easy to migrate because this involves two Gitaly servers, not one.
def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace) def fork_repository(forked_from_storage, path, forked_to_storage, fork_namespace)
gitlab_shell_fast_execute([gitlab_shell_projects_path, 'fork-project', gitlab_shell_fast_execute([gitlab_shell_projects_path, 'fork-project',
forked_from_storage, "#{path}.git", forked_to_storage, forked_from_storage, "#{path}.git", forked_to_storage,
...@@ -185,6 +193,7 @@ module Gitlab ...@@ -185,6 +193,7 @@ module Gitlab
# Ex. # Ex.
# remove_repository("/path/to/storage", "gitlab/gitlab-ci") # remove_repository("/path/to/storage", "gitlab/gitlab-ci")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def remove_repository(storage, name) def remove_repository(storage, name)
gitlab_shell_fast_execute([gitlab_shell_projects_path, gitlab_shell_fast_execute([gitlab_shell_projects_path,
'rm-project', storage, "#{name}.git"]) 'rm-project', storage, "#{name}.git"])
...@@ -294,6 +303,7 @@ module Gitlab ...@@ -294,6 +303,7 @@ module Gitlab
# Ex. # Ex.
# add_namespace("/path/to/storage", "gitlab") # add_namespace("/path/to/storage", "gitlab")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def add_namespace(storage, name) def add_namespace(storage, name)
path = full_path(storage, name) path = full_path(storage, name)
FileUtils.mkdir_p(path, mode: 0770) unless exists?(storage, name) FileUtils.mkdir_p(path, mode: 0770) unless exists?(storage, name)
...@@ -307,6 +317,7 @@ module Gitlab ...@@ -307,6 +317,7 @@ module Gitlab
# Ex. # Ex.
# rm_namespace("/path/to/storage", "gitlab") # rm_namespace("/path/to/storage", "gitlab")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def rm_namespace(storage, name) def rm_namespace(storage, name)
FileUtils.rm_r(full_path(storage, name), force: true) FileUtils.rm_r(full_path(storage, name), force: true)
end end
...@@ -316,6 +327,7 @@ module Gitlab ...@@ -316,6 +327,7 @@ module Gitlab
# Ex. # Ex.
# mv_namespace("/path/to/storage", "gitlab", "gitlabhq") # mv_namespace("/path/to/storage", "gitlab", "gitlabhq")
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def mv_namespace(storage, old_name, new_name) def mv_namespace(storage, old_name, new_name)
return false if exists?(storage, new_name) || !exists?(storage, old_name) return false if exists?(storage, new_name) || !exists?(storage, old_name)
...@@ -341,6 +353,7 @@ module Gitlab ...@@ -341,6 +353,7 @@ module Gitlab
# exists?(storage, 'gitlab') # exists?(storage, 'gitlab')
# exists?(storage, 'gitlab/cookies.git') # exists?(storage, 'gitlab/cookies.git')
# #
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def exists?(storage, dir_name) def exists?(storage, dir_name)
File.exist?(full_path(storage, dir_name)) File.exist?(full_path(storage, dir_name))
end end
......
This diff is collapsed.
...@@ -30,6 +30,15 @@ describe ApplicationController do ...@@ -30,6 +30,15 @@ describe ApplicationController do
expect(controller).not_to receive(:redirect_to) expect(controller).not_to receive(:redirect_to)
controller.send(:check_password_expiration) controller.send(:check_password_expiration)
end end
it 'does not redirect if the user is over their password expiry but sign-in is disabled' do
stub_application_setting(password_authentication_enabled: false)
user.password_expires_at = Time.new(2002)
allow(controller).to receive(:current_user).and_return(user)
expect(controller).not_to receive(:redirect_to)
controller.send(:check_password_expiration)
end
end end
describe "#authenticate_user_from_token!" do describe "#authenticate_user_from_token!" do
......
require 'spec_helper'
describe PasswordsController do
describe '#check_password_authentication_available' do
before do
@request.env["devise.mapping"] = Devise.mappings[:user]
end
context 'when password authentication is disabled' do
it 'prevents a password reset' do
stub_application_setting(password_authentication_enabled: false)
post :create
expect(flash[:alert]).to eq 'Password authentication is unavailable.'
end
end
context 'when reset email belongs to an ldap user' do
let(:user) { create(:omniauth_user, provider: 'ldapmain', email: 'ldapuser@gitlab.com') }
it 'prevents a password reset' do
post :create, user: { email: user.email }
expect(flash[:alert]).to eq 'Password authentication is unavailable.'
end
end
end
end
...@@ -2,13 +2,6 @@ FactoryGirl.define do ...@@ -2,13 +2,6 @@ FactoryGirl.define do
factory :ci_trigger_without_token, class: Ci::Trigger do factory :ci_trigger_without_token, class: Ci::Trigger do
factory :ci_trigger do factory :ci_trigger do
sequence(:token) { |n| "token#{n}" } sequence(:token) { |n| "token#{n}" }
factory :ci_trigger_for_trigger_schedule do
token { SecureRandom.hex(15) }
owner factory: :user
project factory: :project
ref 'master'
end
end end
end end
end end
...@@ -8,8 +8,8 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do ...@@ -8,8 +8,8 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
find(".table.active-tokens") find(".table.active-tokens")
end end
def inactive_impersonation_tokens def no_personal_access_tokens_message
find(".table.inactive-tokens") find(".settings-message")
end end
before do before do
...@@ -60,15 +60,17 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do ...@@ -60,15 +60,17 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do
click_on "Revoke" click_on "Revoke"
expect(inactive_impersonation_tokens).to have_text(impersonation_token.name) expect(page).to have_selector(".settings-message")
expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.")
end end
it "moves expired tokens to the 'inactive' section" do it "removes expired tokens from 'active' section" do
impersonation_token.update(expires_at: 5.days.ago) impersonation_token.update(expires_at: 5.days.ago)
visit admin_user_impersonation_tokens_path(user_id: user.username) visit admin_user_impersonation_tokens_path(user_id: user.username)
expect(inactive_impersonation_tokens).to have_text(impersonation_token.name) expect(page).to have_selector(".settings-message")
expect(no_personal_access_tokens_message).to have_text("This user has no active Impersonation Tokens.")
end end
end end
end end
...@@ -4,6 +4,11 @@ feature 'Merge request conflict resolution', js: true, feature: true do ...@@ -4,6 +4,11 @@ feature 'Merge request conflict resolution', js: true, feature: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project) } let(:project) { create(:project) }
before do
# In order to have the diffs collapsed, we need to disable the increase feature
stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
end
def create_merge_request(source_branch) def create_merge_request(source_branch)
create(:merge_request, source_branch: source_branch, target_branch: 'conflict-start', source_project: project) do |mr| create(:merge_request, source_branch: source_branch, target_branch: 'conflict-start', source_project: project) do |mr|
mr.mark_as_unmergeable mr.mark_as_unmergeable
......
require 'spec_helper' require 'spec_helper'
describe 'Profile > Password', feature: true do describe 'Profile > Password', feature: true do
let(:user) { create(:user, password_automatically_set: true) } context 'Password authentication enabled' do
let(:user) { create(:user, password_automatically_set: true) }
before do before do
sign_in(user) sign_in(user)
visit edit_profile_password_path visit edit_profile_password_path
end end
def fill_passwords(password, confirmation) def fill_passwords(password, confirmation)
fill_in 'New password', with: password fill_in 'New password', with: password
fill_in 'Password confirmation', with: confirmation fill_in 'Password confirmation', with: confirmation
click_button 'Save password' click_button 'Save password'
end end
context 'User with password automatically set' do
describe 'User puts different passwords in the field and in the confirmation' do
it 'shows an error message' do
fill_passwords('mypassword', 'mypassword2')
context 'User with password automatically set' do page.within('.alert-danger') do
describe 'User puts different passwords in the field and in the confirmation' do expect(page).to have_content("Password confirmation doesn't match Password")
it 'shows an error message' do end
fill_passwords('mypassword', 'mypassword2') end
it 'does not contain the current password field after an error' do
fill_passwords('mypassword', 'mypassword2')
page.within('.alert-danger') do expect(page).to have_no_field('user[current_password]')
expect(page).to have_content("Password confirmation doesn't match Password")
end end
end end
it 'does not contain the current password field after an error' do describe 'User puts the same passwords in the field and in the confirmation' do
fill_passwords('mypassword', 'mypassword2') it 'shows a success message' do
fill_passwords('mypassword', 'mypassword')
expect(page).to have_no_field('user[current_password]') page.within('.flash-notice') do
expect(page).to have_content('Password was successfully updated. Please login with it')
end
end
end end
end end
end
describe 'User puts the same passwords in the field and in the confirmation' do context 'Password authentication unavailable' do
it 'shows a success message' do before do
fill_passwords('mypassword', 'mypassword') gitlab_sign_in(user)
end
page.within('.flash-notice') do context 'Regular user' do
expect(page).to have_content('Password was successfully updated. Please login with it') let(:user) { create(:user) }
end
it 'renders 404 when sign-in is disabled' do
stub_application_setting(password_authentication_enabled: false)
visit edit_profile_password_path
expect(page).to have_http_status(404)
end
end
context 'LDAP user' do
let(:user) { create(:omniauth_user, provider: 'ldapmain') }
it 'renders 404' do
visit edit_profile_password_path
expect(page).to have_http_status(404)
end end
end end
end end
......
...@@ -7,8 +7,8 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do ...@@ -7,8 +7,8 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
find(".table.active-tokens") find(".table.active-tokens")
end end
def inactive_personal_access_tokens def no_personal_access_tokens_message
find(".table.inactive-tokens") find(".settings-message")
end end
def created_personal_access_token def created_personal_access_token
...@@ -80,14 +80,16 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do ...@@ -80,14 +80,16 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do
visit profile_personal_access_tokens_path visit profile_personal_access_tokens_path
click_on "Revoke" click_on "Revoke"
expect(inactive_personal_access_tokens).to have_text(personal_access_token.name) expect(page).to have_selector(".settings-message")
expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.")
end end
it "moves expired tokens to the 'inactive' section" do it "removes expired tokens from 'active' section" do
personal_access_token.update(expires_at: 5.days.ago) personal_access_token.update(expires_at: 5.days.ago)
visit profile_personal_access_tokens_path visit profile_personal_access_tokens_path
expect(inactive_personal_access_tokens).to have_text(personal_access_token.name) expect(page).to have_selector(".settings-message")
expect(no_personal_access_tokens_message).to have_text("This user has no active Personal Access Tokens.")
end end
context "when revocation fails" do context "when revocation fails" do
......
...@@ -110,6 +110,10 @@ feature 'Diff file viewer', :js, feature: true do ...@@ -110,6 +110,10 @@ feature 'Diff file viewer', :js, feature: true do
context 'binary file that appears to be text in the first 1024 bytes' do context 'binary file that appears to be text in the first 1024 bytes' do
before do before do
# The file we're visiting is smaller than 10 KB and we want it collapsed
# so we need to disable the size increase feature.
stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c') visit_commit('7b1cf4336b528e0f3d1d140ee50cafdbc703597c')
end end
......
...@@ -30,7 +30,7 @@ feature 'No Password Alert' do ...@@ -30,7 +30,7 @@ feature 'No Password Alert' do
let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') } let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') }
before do before do
stub_application_setting(signin_enabled?: false) stub_application_setting(password_authentication_enabled?: false)
stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config]) stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config])
end end
......
...@@ -35,7 +35,7 @@ describe ButtonHelper do ...@@ -35,7 +35,7 @@ describe ButtonHelper do
context 'with internal auth disabled' do context 'with internal auth disabled' do
before do before do
stub_application_setting(signin_enabled?: false) stub_application_setting(password_authentication_enabled?: false)
end end
context 'when user has no personal access tokens' do context 'when user has no personal access tokens' do
......
...@@ -160,7 +160,7 @@ describe ProjectsHelper do ...@@ -160,7 +160,7 @@ describe ProjectsHelper do
context 'user requires a personal access token' do context 'user requires a personal access token' do
it 'returns true' do it 'returns true' do
stub_application_setting(signin_enabled?: false) stub_application_setting(password_authentication_enabled?: false)
expect(helper.show_no_password_message?).to be_truthy expect(helper.show_no_password_message?).to be_truthy
end end
...@@ -184,7 +184,7 @@ describe ProjectsHelper do ...@@ -184,7 +184,7 @@ describe ProjectsHelper do
let(:user) { create(:user) } let(:user) { create(:user) }
it 'returns link to create a personal access token' do it 'returns link to create a personal access token' do
stub_application_setting(signin_enabled?: false) stub_application_setting(password_authentication_enabled?: false)
expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>} expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>}
end end
......
...@@ -206,7 +206,7 @@ describe Gitlab::Auth, lib: true do ...@@ -206,7 +206,7 @@ describe Gitlab::Auth, lib: true do
end end
it 'throws an error suggesting user create a PAT when internal auth is disabled' do it 'throws an error suggesting user create a PAT when internal auth is disabled' do
allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError) expect { gl_auth.find_for_git_client('foo', 'bar', project: nil, ip: 'ip') }.to raise_error(Gitlab::Auth::MissingPersonalTokenError)
end end
...@@ -279,6 +279,16 @@ describe Gitlab::Auth, lib: true do ...@@ -279,6 +279,16 @@ describe Gitlab::Auth, lib: true do
gl_auth.find_with_user_password('ldap_user', 'password') gl_auth.find_with_user_password('ldap_user', 'password')
end end
end end
context "with sign-in disabled" do
before do
stub_application_setting(password_authentication_enabled: false)
end
it "does not find user by valid login/password" do
expect(gl_auth.find_with_user_password(username, password)).to be_nil
end
end
end end
private private
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::FakeApplicationSettings do describe Gitlab::FakeApplicationSettings do
let(:defaults) { { signin_enabled: false, foobar: 'asdf', signup_enabled: true, 'test?' => 123 } } let(:defaults) { { password_authentication_enabled: false, foobar: 'asdf', signup_enabled: true, 'test?' => 123 } }
subject { described_class.new(defaults) } subject { described_class.new(defaults) }
it 'wraps OpenStruct variables properly' do it 'wraps OpenStruct variables properly' do
expect(subject.signin_enabled).to be_falsey expect(subject.password_authentication_enabled).to be_falsey
expect(subject.signup_enabled).to be_truthy expect(subject.signup_enabled).to be_truthy
expect(subject.foobar).to eq('asdf') expect(subject.foobar).to eq('asdf')
end end
it 'defines predicate methods' do it 'defines predicate methods' do
expect(subject.signin_enabled?).to be_falsey expect(subject.password_authentication_enabled?).to be_falsey
expect(subject.signup_enabled?).to be_truthy expect(subject.signup_enabled?).to be_truthy
end end
it 'predicate method changes when value is updated' do it 'predicate method changes when value is updated' do
subject.signin_enabled = true subject.password_authentication_enabled = true
expect(subject.signin_enabled?).to be_truthy expect(subject.password_authentication_enabled?).to be_truthy
end end
it 'does not define a predicate method' do it 'does not define a predicate method' do
......
...@@ -34,7 +34,7 @@ EOT ...@@ -34,7 +34,7 @@ EOT
describe 'size limit feature toggles' do describe 'size limit feature toggles' do
context 'when the feature gitlab_git_diff_size_limit_increase is enabled' do context 'when the feature gitlab_git_diff_size_limit_increase is enabled' do
before do before do
Feature.enable('gitlab_git_diff_size_limit_increase') stub_feature_flags(gitlab_git_diff_size_limit_increase: true)
end end
it 'returns 200 KB for size_limit' do it 'returns 200 KB for size_limit' do
...@@ -48,7 +48,7 @@ EOT ...@@ -48,7 +48,7 @@ EOT
context 'when the feature gitlab_git_diff_size_limit_increase is disabled' do context 'when the feature gitlab_git_diff_size_limit_increase is disabled' do
before do before do
Feature.disable('gitlab_git_diff_size_limit_increase') stub_feature_flags(gitlab_git_diff_size_limit_increase: false)
end end
it 'returns 100 KB for size_limit' do it 'returns 100 KB for size_limit' do
......
...@@ -705,9 +705,9 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -705,9 +705,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
# Add new commits so that there's a renamed file in the commit history # Add new commits so that there's a renamed file in the commit history
repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH).rugged repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH).rugged
commit_with_old_name = new_commit_edit_old_file(repo) commit_with_old_name = Gitlab::Git::Commit.decorate(new_commit_edit_old_file(repo))
rename_commit = new_commit_move_file(repo) rename_commit = Gitlab::Git::Commit.decorate(new_commit_move_file(repo))
commit_with_new_name = new_commit_edit_new_file(repo) commit_with_new_name = Gitlab::Git::Commit.decorate(new_commit_edit_new_file(repo))
end end
after(:context) do after(:context) do
...@@ -880,8 +880,8 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -880,8 +880,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
context "compare results between log_by_walk and log_by_shell" do context "compare results between log_by_walk and log_by_shell" do
let(:options) { { ref: "master" } } let(:options) { { ref: "master" } }
let(:commits_by_walk) { repository.log(options).map(&:oid) } let(:commits_by_walk) { repository.log(options).map(&:id) }
let(:commits_by_shell) { repository.log(options.merge({ disable_walk: true })).map(&:oid) } let(:commits_by_shell) { repository.log(options.merge({ disable_walk: true })).map(&:id) }
it { expect(commits_by_walk).to eq(commits_by_shell) } it { expect(commits_by_walk).to eq(commits_by_shell) }
...@@ -924,7 +924,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -924,7 +924,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(commits.size).to be > 0 expect(commits.size).to be > 0
expect(commits).to satisfy do |commits| expect(commits).to satisfy do |commits|
commits.all? { |commit| commit.time >= options[:after] } commits.all? { |commit| commit.committed_date >= options[:after] }
end end
end end
end end
...@@ -937,7 +937,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -937,7 +937,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(commits.size).to be > 0 expect(commits.size).to be > 0
expect(commits).to satisfy do |commits| expect(commits).to satisfy do |commits|
commits.all? { |commit| commit.time <= options[:before] } commits.all? { |commit| commit.committed_date <= options[:before] }
end end
end end
end end
...@@ -946,7 +946,7 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -946,7 +946,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } } let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
def commit_files(commit) def commit_files(commit)
commit.diff(commit.parent_ids.first).deltas.flat_map do |delta| commit.diff_from_parent.deltas.flat_map do |delta|
[delta.old_file[:path], delta.new_file[:path]].uniq.compact [delta.old_file[:path], delta.new_file[:path]].uniq.compact
end end
end end
......
require 'spec_helper'
describe Sortable do
let(:relation) { Issue.all }
describe '#where' do
it 'orders by id, descending' do
order_node = relation.where(iid: 1).order_values.first
expect(order_node).to be_a(Arel::Nodes::Descending)
expect(order_node.expr.name).to eq(:id)
end
end
describe '#find_by' do
it 'does not order' do
expect(relation).to receive(:unscope).with(:order).and_call_original
relation.find_by(iid: 1)
end
end
end
...@@ -23,38 +23,29 @@ describe GitlabIssueTrackerService, models: true do ...@@ -23,38 +23,29 @@ describe GitlabIssueTrackerService, models: true do
describe 'project and issue urls' do describe 'project and issue urls' do
let(:project) { create(:empty_project) } let(:project) { create(:empty_project) }
let(:service) { project.create_gitlab_issue_tracker_service(active: true) }
context 'with absolute urls' do context 'with absolute urls' do
before do before do
GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root" allow(GitlabIssueTrackerService).to receive(:default_url_options).and_return(script_name: "/gitlab/root")
@service = project.create_gitlab_issue_tracker_service(active: true)
end
after do
@service.destroy!
end end
it 'gives the correct path' do it 'gives the correct path' do
expect(@service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues") expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues")
expect(@service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new") expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new")
expect(@service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432") expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432")
end end
end end
context 'with relative urls' do context 'with relative urls' do
before do before do
GitlabIssueTrackerService.default_url_options[:script_name] = "/gitlab/root" allow(GitlabIssueTrackerService).to receive(:default_url_options).and_return(script_name: "/gitlab/root")
@service = project.create_gitlab_issue_tracker_service(active: true)
end
after do
@service.destroy!
end end
it 'gives the correct path' do it 'gives the correct path' do
expect(@service.project_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues") expect(service.project_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues")
expect(@service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new") expect(service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new")
expect(@service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432") expect(service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432")
end end
end end
end end
......
...@@ -2055,6 +2055,28 @@ describe User, models: true do ...@@ -2055,6 +2055,28 @@ describe User, models: true do
end end
end end
describe '#allow_password_authentication?' do
context 'regular user' do
let(:user) { build(:user) }
it 'returns true when sign-in is enabled' do
expect(user.allow_password_authentication?).to be_truthy
end
it 'returns false when sign-in is disabled' do
stub_application_setting(password_authentication_enabled: false)
expect(user.allow_password_authentication?).to be_falsey
end
end
it 'returns false for ldap user' do
user = create(:omniauth_user, provider: 'ldapmain')
expect(user.allow_password_authentication?).to be_falsey
end
end
describe '#forget_me!' do describe '#forget_me!' do
subject { create(:user, remember_created_at: Time.now) } subject { create(:user, remember_created_at: Time.now) }
......
...@@ -35,6 +35,17 @@ describe API::Internal do ...@@ -35,6 +35,17 @@ describe API::Internal do
expect(json_response).to be_empty expect(json_response).to be_empty
end end
end end
context 'nil broadcast message' do
it 'returns nothing' do
allow(BroadcastMessage).to receive(:current).and_return(nil)
get api('/internal/broadcast_message'), secret_token: secret_token
expect(response).to have_http_status(200)
expect(json_response).to be_empty
end
end
end end
describe 'GET /internal/broadcast_messages' do describe 'GET /internal/broadcast_messages' do
......
...@@ -13,6 +13,7 @@ describe API::Settings, 'Settings' do ...@@ -13,6 +13,7 @@ describe API::Settings, 'Settings' do
expect(json_response['default_projects_limit']).to eq(42) expect(json_response['default_projects_limit']).to eq(42)
expect(json_response['signin_enabled']).to be_truthy expect(json_response['signin_enabled']).to be_truthy
expect(json_response['repository_storages']).to eq(['default']) expect(json_response['repository_storages']).to eq(['default'])
expect(json_response['password_authentication_enabled']).to be_truthy
expect(json_response['koding_enabled']).to be_falsey expect(json_response['koding_enabled']).to be_falsey
expect(json_response['koding_url']).to be_nil expect(json_response['koding_url']).to be_nil
expect(json_response['plantuml_enabled']).to be_falsey expect(json_response['plantuml_enabled']).to be_falsey
...@@ -33,8 +34,8 @@ describe API::Settings, 'Settings' do ...@@ -33,8 +34,8 @@ describe API::Settings, 'Settings' do
it "updates application settings" do it "updates application settings" do
put api("/application/settings", admin), put api("/application/settings", admin),
default_projects_limit: 3, default_projects_limit: 3,
signin_enabled: false,
repository_storages: ['custom'], repository_storages: ['custom'],
password_authentication_enabled: false,
koding_enabled: true, koding_enabled: true,
koding_url: 'http://koding.example.com', koding_url: 'http://koding.example.com',
plantuml_enabled: true, plantuml_enabled: true,
...@@ -48,6 +49,7 @@ describe API::Settings, 'Settings' do ...@@ -48,6 +49,7 @@ describe API::Settings, 'Settings' do
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['default_projects_limit']).to eq(3) expect(json_response['default_projects_limit']).to eq(3)
expect(json_response['signin_enabled']).to be_falsey expect(json_response['signin_enabled']).to be_falsey
expect(json_response['password_authentication_enabled']).to be_falsey
expect(json_response['repository_storages']).to eq(['custom']) expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['koding_enabled']).to be_truthy expect(json_response['koding_enabled']).to be_truthy
expect(json_response['koding_url']).to eq('http://koding.example.com') expect(json_response['koding_url']).to eq('http://koding.example.com')
......
...@@ -11,7 +11,7 @@ describe API::V3::Settings, 'Settings' do ...@@ -11,7 +11,7 @@ describe API::V3::Settings, 'Settings' do
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response).to be_an Hash expect(json_response).to be_an Hash
expect(json_response['default_projects_limit']).to eq(42) expect(json_response['default_projects_limit']).to eq(42)
expect(json_response['signin_enabled']).to be_truthy expect(json_response['password_authentication_enabled']).to be_truthy
expect(json_response['repository_storage']).to eq('default') expect(json_response['repository_storage']).to eq('default')
expect(json_response['koding_enabled']).to be_falsey expect(json_response['koding_enabled']).to be_falsey
expect(json_response['koding_url']).to be_nil expect(json_response['koding_url']).to be_nil
...@@ -29,12 +29,12 @@ describe API::V3::Settings, 'Settings' do ...@@ -29,12 +29,12 @@ describe API::V3::Settings, 'Settings' do
it "updates application settings" do it "updates application settings" do
put v3_api("/application/settings", admin), put v3_api("/application/settings", admin),
default_projects_limit: 3, signin_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com', default_projects_limit: 3, password_authentication_enabled: false, repository_storage: 'custom', koding_enabled: true, koding_url: 'http://koding.example.com',
plantuml_enabled: true, plantuml_url: 'http://plantuml.example.com' plantuml_enabled: true, plantuml_url: 'http://plantuml.example.com'
expect(response).to have_http_status(200) expect(response).to have_http_status(200)
expect(json_response['default_projects_limit']).to eq(3) expect(json_response['default_projects_limit']).to eq(3)
expect(json_response['signin_enabled']).to be_falsey expect(json_response['password_authentication_enabled']).to be_falsey
expect(json_response['repository_storage']).to eq('custom') expect(json_response['repository_storage']).to eq('custom')
expect(json_response['repository_storages']).to eq(['custom']) expect(json_response['repository_storages']).to eq(['custom'])
expect(json_response['koding_enabled']).to be_truthy expect(json_response['koding_enabled']).to be_truthy
......
...@@ -463,7 +463,7 @@ describe 'Git HTTP requests', lib: true do ...@@ -463,7 +463,7 @@ describe 'Git HTTP requests', lib: true do
context 'when internal auth is disabled' do context 'when internal auth is disabled' do
before do before do
allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
end end
it 'rejects pulls with personal access token error message' do it 'rejects pulls with personal access token error message' do
......
...@@ -101,7 +101,7 @@ describe JwtController do ...@@ -101,7 +101,7 @@ describe JwtController do
context 'when internal auth is disabled' do context 'when internal auth is disabled' do
it 'rejects the authorization attempt with personal access token message' do it 'rejects the authorization attempt with personal access token message' do
allow_any_instance_of(ApplicationSetting).to receive(:signin_enabled?) { false } allow_any_instance_of(ApplicationSetting).to receive(:password_authentication_enabled?) { false }
get '/jwt/auth', parameters, headers get '/jwt/auth', parameters, headers
expect(response).to have_http_status(401) expect(response).to have_http_status(401)
......
...@@ -59,6 +59,7 @@ RSpec.configure do |config| ...@@ -59,6 +59,7 @@ RSpec.configure do |config|
config.include ApiHelpers, :api config.include ApiHelpers, :api
config.include Gitlab::Routing, type: :routing config.include Gitlab::Routing, type: :routing
config.include MigrationsHelpers, :migration config.include MigrationsHelpers, :migration
config.include StubFeatureFlags
config.include EE::LicenseHelpers config.include EE::LicenseHelpers
config.include Rails.application.routes.url_helpers, type: :routing config.include Rails.application.routes.url_helpers, type: :routing
...@@ -86,6 +87,8 @@ RSpec.configure do |config| ...@@ -86,6 +87,8 @@ RSpec.configure do |config|
config.before(:example) do config.before(:example) do
# Skip pre-receive hook check so we can use the web editor and merge. # Skip pre-receive hook check so we can use the web editor and merge.
allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil]) allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil])
# Enable all features by default for testing
allow(Feature).to receive(:enabled?) { true }
end end
config.before(:example, :request_store) do config.before(:example, :request_store) do
......
module StubFeatureFlags
def stub_feature_flags(features)
features.each do |feature_name, enabled|
allow(Feature).to receive(:enabled?).with(feature_name) { enabled }
allow(Feature).to receive(:enabled?).with(feature_name.to_s) { enabled }
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment