diff options
37 files changed, 311 insertions, 129 deletions
diff --git a/CHANGELOG b/CHANGELOG index 386ce7ca6d4..d7d1eb7ab41 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.0.0 (unreleased) + - Upgrade gitlab_git to 7.2.15 to fix `git blame` errors with ISO-encoded files (Stan Hu) - Prevent too many redirects upon login when home page URL is set to external_url (Stan Hu) - Improve dropdown positioning on the project home page (Hannes Rosenögger) - Upgrade browser gem to 1.0.0 to avoid warning in IE11 compatibilty mode (Stan Hu) @@ -22,6 +23,9 @@ v 8.0.0 (unreleased) - Fix 500 error when submit project snippet without body - Improve search page usability - Bring more UI consistency in way how projects, snippets and groups lists are rendered + - Make all profiles public + - Fixed login failure when extern_uid changes (Joel Koglin) + - Don't notify users without access to the project when they are (accidentally) mentioned in a note. v 7.14.1 - Improve abuse reports management from admin area @@ -38,7 +38,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.14' +gem "gitlab_git", '~> 7.2.15' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes diff --git a/Gemfile.lock b/Gemfile.lock index bedcf9c85b0..d09bc53e379 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -274,7 +274,7 @@ GEM mime-types (~> 1.19) gitlab_emoji (0.1.0) gemojione (~> 2.0) - gitlab_git (7.2.14) + gitlab_git (7.2.15) activesupport (~> 4.0) charlock_holmes (~> 0.6) gitlab-linguist (~> 3.0) @@ -787,7 +787,7 @@ DEPENDENCIES gitlab-flowdock-git-hook (~> 1.0.1) gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.1) - gitlab_git (~> 7.2.14) + gitlab_git (~> 7.2.15) gitlab_meta (= 7.0) gitlab_omniauth-ldap (= 1.2.1) gollum-lib (~> 4.0.2) diff --git a/app/assets/javascripts/syntax_highlight.coffee b/app/assets/javascripts/syntax_highlight.coffee new file mode 100644 index 00000000000..510f15d1b49 --- /dev/null +++ b/app/assets/javascripts/syntax_highlight.coffee @@ -0,0 +1,9 @@ +# Applies a syntax highlighting color scheme CSS class to any element with the +# `js-syntax-highlight` class +# +# ### Example Markup +# +# <div class="js-syntax-highlight"></div> +# +$(document).on 'ready page:load', -> + $('.js-syntax-highlight').addClass(gon.user_color_scheme) diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss index 2674fde41ae..e5902597c4d 100644 --- a/app/assets/stylesheets/generic/common.scss +++ b/app/assets/stylesheets/generic/common.scss @@ -132,10 +132,6 @@ p.time { text-shadow: none; } -.highlight_word { - background: #fafe3d; -} - .thin_area{ height: 150px; } diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index c8cb18ec35f..8323a8598ec 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -21,6 +21,12 @@ pre.code.highlight.dark, background-color: #557 !important; } + // Search result highlight + span.highlight_word { + background: #ffe792; + color: #000000; + } + .hll { background-color: #373b41 } .c { color: #969896 } /* Comment */ .err { color: #cc6666 } /* Error */ diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss index 001e8b31020..e8381674336 100644 --- a/app/assets/stylesheets/highlight/monokai.scss +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -21,6 +21,12 @@ pre.code.monokai, background-color: #49483e !important; } + // Search result highlight + span.highlight_word { + background: #ffe792; + color: #000000; + } + .hll { background-color: #49483e } .c { color: #75715e } /* Comment */ .err { color: #960050; background-color: #1e0010 } /* Error */ diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss index f5b827e7c02..bd41480aefb 100644 --- a/app/assets/stylesheets/highlight/solarized_dark.scss +++ b/app/assets/stylesheets/highlight/solarized_dark.scss @@ -21,6 +21,11 @@ pre.code.highlight.solarized-dark, background-color: #174652 !important; } + // Search result highlight + span.highlight_word { + background: #094554; + } + /* Solarized Dark For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index 6b44c00c305..4cc62863870 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -21,6 +21,11 @@ pre.code.highlight.solarized-light, background-color: #ddd8c5 !important; } + // Search result highlight + span.highlight_word { + background: #eee8d5; + } + /* Solarized Light For use with Jekyll and Pygments diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index a52ffc971d1..e0edfb80b42 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -21,6 +21,11 @@ pre.code.highlight.white, background-color: #f8eec7 !important; } + // Search result highlight + span.highlight_word { + background: #fafe3d; + } + .hll { background-color: #f8f8f8 } .c { color: #999988; font-style: italic; } .err { color: #a61717; background-color: #e3d2d2; } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index ef1170e16da..cb1cf13d34d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -192,11 +192,12 @@ class ApplicationController < ActionController::Base end def add_gon_variables + gon.api_version = API::API.version + gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s gon.default_issues_tracker = Project.new.default_issue_tracker.to_param - gon.api_version = API::API.version - gon.relative_url_root = Gitlab.config.gitlab.relative_url_root - gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s - gon.max_file_size = current_application_settings.max_attachment_size; + gon.max_file_size = current_application_settings.max_attachment_size + gon.relative_url_root = Gitlab.config.gitlab.relative_url_root + gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class if current_user gon.current_user_id = current_user.id diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 2bb5c338cf6..1484356a7f4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -51,10 +51,6 @@ class UsersController < ApplicationController def set_user @user = User.find_by_username!(params[:username]) - - unless current_user || @user.public_profile? - return authenticate_user! - end end def authorized_projects_ids diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index eb3f72a307d..114730eb948 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -58,7 +58,7 @@ module GitlabMarkdownHelper @options = options # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch - rend = Redcarpet::Render::GitlabHTML.new(self, user_color_scheme_class, options) + rend = Redcarpet::Render::GitlabHTML.new(self, options) # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use @markdown = Redcarpet::Markdown.new(rend, MARKDOWN_OPTIONS) diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb index ea774e28ecf..7f1b6a69926 100644 --- a/app/helpers/preferences_helper.rb +++ b/app/helpers/preferences_helper.rb @@ -1,25 +1,5 @@ # Helper methods for per-User preferences module PreferencesHelper - COLOR_SCHEMES = { - 1 => 'white', - 2 => 'dark', - 3 => 'solarized-light', - 4 => 'solarized-dark', - 5 => 'monokai', - } - COLOR_SCHEMES.default = 'white' - - # Helper method to access the COLOR_SCHEMES - # - # The keys are the `color_scheme_ids` - # The values are the `name` of the scheme. - # - # The preview images are `name-scheme-preview.png` - # The stylesheets should use the css class `.name` - def color_schemes - COLOR_SCHEMES.freeze - end - # Maps `dashboard` values to more user-friendly option text DASHBOARD_CHOICES = { projects: 'Your Projects (default)', @@ -50,12 +30,11 @@ module PreferencesHelper end def user_application_theme - theme = Gitlab::Themes.by_id(current_user.try(:theme_id)) - theme.css_class + Gitlab::Themes.for_user(current_user).css_class end - def user_color_scheme_class - COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) + def user_color_scheme + Gitlab::ColorSchemes.for_user(current_user).css_class end def prefer_readme? diff --git a/app/models/user.rb b/app/models/user.rb index f70761074c5..48e0e6ed48b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -104,7 +104,7 @@ class User < ActiveRecord::Base # Profile has_many :keys, dependent: :destroy has_many :emails, dependent: :destroy - has_many :identities, dependent: :destroy + has_many :identities, dependent: :destroy, autosave: true # Groups has_many :members, dependent: :destroy @@ -637,10 +637,6 @@ class User < ActiveRecord::Base email.start_with?('temp-email-for-oauth') end - def public_profile? - authorized_projects.public_only.any? - end - def avatar_url(size = nil) if avatar.present? [gitlab_config.url, avatar.url].join diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 3735a136365..e294b23bc23 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -107,12 +107,17 @@ class NotificationService recipients = [] + mentioned_users = note.mentioned_users + mentioned_users.select! do |user| + user.can?(:read_project, note.project) + end + # Add all users participating in the thread (author, assignee, comment authors) participants = if target.respond_to?(:participants) target.participants(note.author) else - note.mentioned_users + mentioned_users end recipients = recipients.concat(participants) @@ -120,8 +125,8 @@ class NotificationService recipients = add_project_watchers(recipients, note.project) # Reject users with Mention notification level, except those mentioned in _this_ note. - recipients = reject_mention_users(recipients - note.mentioned_users, note.project) - recipients = recipients + note.mentioned_users + recipients = reject_mention_users(recipients - mentioned_users, note.project) + recipients = recipients + mentioned_users recipients = reject_muted_users(recipients, note.project) diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml index 1134317ee06..aa0361a0a1b 100644 --- a/app/views/profiles/preferences/show.html.haml +++ b/app/views/profiles/preferences/show.html.haml @@ -22,11 +22,11 @@ .panel-heading Syntax highlighting theme .panel-body - - color_schemes.each do |color_scheme_id, color_scheme| + - Gitlab::ColorSchemes.each do |scheme| = label_tag do - .preview= image_tag "#{color_scheme}-scheme-preview.png" - = f.radio_button :color_scheme_id, color_scheme_id - = color_scheme.tr('-_', ' ').titleize + .preview= image_tag "#{scheme.css_class}-scheme-preview.png" + = f.radio_button :color_scheme_id, scheme.id + = scheme.name .panel.panel-default .panel-heading diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index 9fdeddfcc7a..c519e52e596 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -100,11 +100,6 @@ %hr = link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" - - if @user.public_profile? - .alert.alert-info - %h4 Public profile - %p Your profile is publicly visible because you joined public project(s) - .row .col-md-7 diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml index 58f58eff54d..0fe8a3b490a 100644 --- a/app/views/search/results/_blob.html.haml +++ b/app/views/search/results/_blob.html.haml @@ -7,4 +7,4 @@ %strong = blob.filename .file-content.code.term - = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline, user_color_scheme_class: 'white' + = render 'shared/file_highlight', blob: blob, first_line_number: blob.startline diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml index 95099853918..9a4f9fb9485 100644 --- a/app/views/search/results/_snippet_blob.html.haml +++ b/app/views/search/results/_snippet_blob.html.haml @@ -23,7 +23,7 @@ .nothing-here-block Empty file - else .file-content.code - %div.highlighted-data{class: user_color_scheme_class} + %div.highlighted-data{ class: user_color_scheme } .line-numbers - snippet_blob[:snippet_chunks].each do |snippet| - unless snippet[:data].empty? diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml index c03438eb952..f5859481d46 100644 --- a/app/views/search/results/_wiki_blob.html.haml +++ b/app/views/search/results/_wiki_blob.html.haml @@ -7,4 +7,4 @@ %strong = wiki_blob.filename .file-content.code.term - = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline, user_color_scheme_class: 'white' + = render 'shared/file_highlight', blob: wiki_blob, first_line_number: wiki_blob.startline diff --git a/app/views/shared/_file_highlight.html.haml b/app/views/shared/_file_highlight.html.haml index d6a2e177da1..57c3aff3e18 100644 --- a/app/views/shared/_file_highlight.html.haml +++ b/app/views/shared/_file_highlight.html.haml @@ -1,4 +1,4 @@ -.file-content.code{class: user_color_scheme_class} +.file-content.code.js-syntax-highlight{ class: user_color_scheme } .line-numbers - if blob.data.present? - blob.data.lines.each_index do |index| diff --git a/db/migrate/20150817163600_deduplicate_user_identities.rb b/db/migrate/20150817163600_deduplicate_user_identities.rb new file mode 100644 index 00000000000..fab669c2905 --- /dev/null +++ b/db/migrate/20150817163600_deduplicate_user_identities.rb @@ -0,0 +1,14 @@ +class DeduplicateUserIdentities < ActiveRecord::Migration + def change + execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;' + execute 'CREATE TEMPORARY TABLE tt_migration_DeduplicateUserIdentities AS SELECT id,provider,user_id FROM identities;' + execute 'DELETE FROM identities WHERE id NOT IN ( SELECT MIN(id) FROM tt_migration_DeduplicateUserIdentities GROUP BY user_id, provider);' + execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;' + end + + def down + # This is an irreversible migration; + # If someone is trying to rollback for other reasons, we should not throw an Exception. + # raise ActiveRecord::IrreversibleMigration + end +end diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index 3efa92cb868..2d77c6d1172 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -17,4 +17,4 @@ If you want to import from a GitHub Enterprise instance, you need to use GitLab * To import a project, you can simple click "Add". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data.
### Note
-When you import your projects from GitHub, it is not possible to keep your labels and milestones and issue numbers won't match. We are working on improving this in the near future.
+When you import your projects from GitHub, it is not possible to keep your labels and milestones. We are working on improving this in the near future.
diff --git a/features/user.feature b/features/user.feature index 69618e929c4..35eae842e77 100644 --- a/features/user.feature +++ b/features/user.feature @@ -14,11 +14,6 @@ Feature: User And I should not see project "Internal" And I should see project "Community" - Scenario: I visit user "John Doe" page while not signed in when he is not authorized to a public project - Given "John Doe" owns internal project "Internal" - When I visit user "John Doe" page - Then I should be redirected to sign in page - # Signed in as someone else Scenario: I visit user "John Doe" page while signed in as someone else when he owns a public project diff --git a/lib/gitlab/color_schemes.rb b/lib/gitlab/color_schemes.rb new file mode 100644 index 00000000000..9c4664df903 --- /dev/null +++ b/lib/gitlab/color_schemes.rb @@ -0,0 +1,67 @@ +module Gitlab + # Module containing GitLab's syntax color scheme definitions and helper + # methods for accessing them. + module ColorSchemes + # Struct class representing a single Scheme + Scheme = Struct.new(:id, :name, :css_class) + + SCHEMES = [ + Scheme.new(1, 'White', 'white'), + Scheme.new(2, 'Dark', 'dark'), + Scheme.new(3, 'Solarized Light', 'solarized-light'), + Scheme.new(4, 'Solarized Dark', 'solarized-dark'), + Scheme.new(5, 'Monokai', 'monokai') + ].freeze + + # Convenience method to get a space-separated String of all the color scheme + # classes that might be applied to a code block. + # + # Returns a String + def self.body_classes + SCHEMES.collect(&:css_class).uniq.join(' ') + end + + # Get a Scheme by its ID + # + # If the ID is invalid, returns the default Scheme. + # + # id - Integer ID + # + # Returns a Scheme + def self.by_id(id) + SCHEMES.detect { |s| s.id == id } || default + end + + # Returns the number of defined Schemes + def self.count + SCHEMES.size + end + + # Get the default Scheme + # + # Returns a Scheme + def self.default + by_id(1) + end + + # Iterate through each Scheme + # + # Yields the Scheme object + def self.each(&block) + SCHEMES.each(&block) + end + + # Get the Scheme for the specified user, or the default + # + # user - User record + # + # Returns a Scheme + def self.for_user(user) + if user + by_id(user.color_scheme_id) + else + default + end + end + end +end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 1a2a50a14d0..7ad3ed8728f 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -4,7 +4,7 @@ module Gitlab key = :current_application_settings RequestStore.store[key] ||= begin - if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.table_exists?('application_settings') + if ActiveRecord::Base.connection.active? && ActiveRecord::Base.connection.table_exists?('application_settings') ApplicationSetting.current || ApplicationSetting.create_from_defaults else fake_application_settings diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index f7f3ba9ad7d..04a22237478 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -44,9 +44,14 @@ module Gitlab gl_user.skip_reconfirmation! gl_user.email = auth_hash.email - # Build new identity only if we dont have have same one - gl_user.identities.find_or_initialize_by(provider: auth_hash.provider, - extern_uid: auth_hash.uid) + # find_or_initialize_by doesn't update `gl_user.identities`, and isn't autosaved. + identity = gl_user.identities.find { |identity| identity.provider == auth_hash.provider } + identity ||= gl_user.identities.build(provider: auth_hash.provider) + + # For a new user set extern_uid to the LDAP DN + # For an existing user with matching email but changed DN, update the DN. + # For an existing user with no change in DN, this line changes nothing. + identity.extern_uid = auth_hash.uid gl_user end diff --git a/lib/gitlab/themes.rb b/lib/gitlab/themes.rb index 5209df92795..83f91de810c 100644 --- a/lib/gitlab/themes.rb +++ b/lib/gitlab/themes.rb @@ -37,6 +37,11 @@ module Gitlab THEMES.detect { |t| t.id == id } || default end + # Returns the number of defined Themes + def self.count + THEMES.size + end + # Get the default Theme # # Returns a Theme @@ -51,6 +56,19 @@ module Gitlab THEMES.each(&block) end + # Get the Theme for the specified user, or the default + # + # user - User record + # + # Returns a Theme + def self.for_user(user) + if user + by_id(user.theme_id) + else + default + end + end + private def self.default_id diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb index f57b56cbdf0..9cb8e91d6e3 100644 --- a/lib/redcarpet/render/gitlab_html.rb +++ b/lib/redcarpet/render/gitlab_html.rb @@ -4,9 +4,8 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML attr_reader :template alias_method :h, :template - def initialize(template, color_scheme, options = {}) + def initialize(template, options = {}) @template = template - @color_scheme = color_scheme @options = options.dup @options.reverse_merge!( @@ -35,7 +34,7 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML end formatter = Rouge::Formatters::HTMLGitlab.new( - cssclass: "code highlight #{@color_scheme} #{lexer.tag}" + cssclass: "code highlight js-syntax-highlight #{lexer.tag}" ) formatter.format(lexer.lex(code)) end diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index 3da4dfc2b23..4fe019f8342 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -64,8 +64,8 @@ describe 'GitLab Markdown', feature: true do it 'parses fenced code blocks' do aggregate_failures do - expect(doc).to have_selector('pre.code.highlight.white.c') - expect(doc).to have_selector('pre.code.highlight.white.python') + expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.c') + expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.python') end end @@ -224,8 +224,4 @@ describe 'GitLab Markdown', feature: true do def current_user @feat.user end - - def user_color_scheme_class - :white - end end diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index da58ab98462..e68a5ec29ab 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -28,8 +28,7 @@ describe EventsHelper do it 'should display the first line of a code block' do input = "```\nCode block\nwith two lines\n```" - expected = '<pre class="code highlight white plaintext"><code>' \ - 'Code block...</code></pre>' + expected = %r{<pre.+><code>Code block\.\.\.</code></pre>} expect(event_note(input)).to match(expected) end @@ -55,7 +54,7 @@ describe EventsHelper do it 'should preserve code color scheme' do input = "```ruby\ndef test\n 'hello world'\nend\n```" - expected = '<pre class="code highlight white ruby">' \ + expected = '<pre class="code highlight js-syntax-highlight ruby">' \ "<code><span class=\"k\">def</span> <span class=\"nf\">test</span>\n" \ " <span class=\"s1\">\'hello world\'</span>\n" \ "<span class=\"k\">end</span>" \ diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index d814b562113..06f69262b71 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -1,72 +1,82 @@ require 'spec_helper' describe PreferencesHelper do + describe 'dashboard_choices' do + it 'raises an exception when defined choices may be missing' do + expect(User).to receive(:dashboards).and_return(foo: 'foo') + expect { helper.dashboard_choices }.to raise_error(RuntimeError) + end + + it 'raises an exception when defined choices may be using the wrong key' do + expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar') + expect { helper.dashboard_choices }.to raise_error(KeyError) + end + + it 'provides better option descriptions' do + expect(helper.dashboard_choices).to match_array [ + ['Your Projects (default)', 'projects'], + ['Starred Projects', 'stars'] + ] + end + end + describe 'user_application_theme' do context 'with a user' do it "returns user's theme's css_class" do - user = double('user', theme_id: 3) - allow(self).to receive(:current_user).and_return(user) - expect(user_application_theme).to eq 'ui_green' + stub_user(theme_id: 3) + + expect(helper.user_application_theme).to eq 'ui_green' end it 'returns the default when id is invalid' do - user = double('user', theme_id: Gitlab::Themes::THEMES.size + 5) + stub_user(theme_id: Gitlab::Themes.count + 5) allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(2) - allow(self).to receive(:current_user).and_return(user) - expect(user_application_theme).to eq 'ui_charcoal' + expect(helper.user_application_theme).to eq 'ui_charcoal' end end context 'without a user' do - before do - allow(self).to receive(:current_user).and_return(nil) - end - it 'returns the default theme' do - expect(user_application_theme).to eq Gitlab::Themes.default.css_class + stub_user + + expect(helper.user_application_theme).to eq Gitlab::Themes.default.css_class end end end - describe 'dashboard_choices' do - it 'raises an exception when defined choices may be missing' do - expect(User).to receive(:dashboards).and_return(foo: 'foo') - expect { dashboard_choices }.to raise_error(RuntimeError) - end + describe 'user_color_scheme' do + context 'with a user' do + it "returns user's scheme's css_class" do + allow(helper).to receive(:current_user). + and_return(double(color_scheme_id: 3)) - it 'raises an exception when defined choices may be using the wrong key' do - expect(User).to receive(:dashboards).and_return(foo: 'foo', bar: 'bar') - expect { dashboard_choices }.to raise_error(KeyError) - end + expect(helper.user_color_scheme).to eq 'solarized-light' + end - it 'provides better option descriptions' do - expect(dashboard_choices).to match_array [ - ['Your Projects (default)', 'projects'], - ['Starred Projects', 'stars'] - ] + it 'returns the default when id is invalid' do + allow(helper).to receive(:current_user). + and_return(double(color_scheme_id: Gitlab::ColorSchemes.count + 5)) + end end - end - describe 'user_color_scheme_class' do - context 'with current_user is nil' do - it 'should return a string' do - allow(self).to receive(:current_user).and_return(nil) - expect(user_color_scheme_class).to be_kind_of(String) + context 'without a user' do + it 'returns the default theme' do + stub_user + + expect(helper.user_color_scheme). + to eq Gitlab::ColorSchemes.default.css_class end end + end - context 'with a current_user' do - (1..5).each do |color_scheme_id| - context "with color_scheme_id == #{color_scheme_id}" do - it 'should return a string' do - current_user = double(color_scheme_id: color_scheme_id) - allow(self).to receive(:current_user).and_return(current_user) - expect(user_color_scheme_class).to be_kind_of(String) - end - end - end + def stub_user(messages = {}) + if messages.empty? + allow(helper).to receive(:current_user).and_return(nil) + else + allow(helper).to receive(:current_user). + and_return(double('user', messages)) end end end diff --git a/spec/lib/gitlab/color_schemes_spec.rb b/spec/lib/gitlab/color_schemes_spec.rb new file mode 100644 index 00000000000..c7be45dbcd3 --- /dev/null +++ b/spec/lib/gitlab/color_schemes_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe Gitlab::ColorSchemes do + describe '.body_classes' do + it 'returns a space-separated list of class names' do + css = described_class.body_classes + + expect(css).to include('white') + expect(css).to include(' solarized-light ') + expect(css).to include(' monokai') + end + end + + describe '.by_id' do + it 'returns a scheme by its ID' do + expect(described_class.by_id(1).name).to eq 'White' + expect(described_class.by_id(4).name).to eq 'Solarized Dark' + end + end + + describe '.default' do + it 'returns the default scheme' do + expect(described_class.default.id).to eq 1 + end + end + + describe '.each' do + it 'passes the block to the SCHEMES Array' do + ids = [] + described_class.each { |scheme| ids << scheme.id } + expect(ids).not_to be_empty + end + end + + describe '.for_user' do + it 'returns default when user is nil' do + expect(described_class.for_user(nil).id).to eq 1 + end + + it "returns user's preferred color scheme" do + user = double(color_scheme_id: 5) + expect(described_class.for_user(user).id).to eq 5 + end + end +end diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index 7cfca96f4e0..84d9fb54b61 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -47,6 +47,28 @@ describe Gitlab::LDAP::User do expect(existing_user.ldap_identity.provider).to eql 'ldapmain' end + it 'connects to existing ldap user if the extern_uid changes' do + existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain') + expect{ ldap_user.save }.not_to change{ User.count } + + existing_user.reload + expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid' + expect(existing_user.ldap_identity.provider).to eql 'ldapmain' + expect(existing_user.id).to eql ldap_user.gl_user.id + end + + it 'maintains an identity per provider' do + existing_user = create(:omniauth_user, email: 'john@example.com', provider: 'twitter') + expect(existing_user.identities.count).to eql(1) + + ldap_user.save + expect(ldap_user.gl_user.identities.count).to eql(2) + + # Expect that find_by provider only returns a single instance of an identity and not an Enumerable + expect(ldap_user.gl_user.identities.find_by(provider: 'twitter')).to be_instance_of Identity + expect(ldap_user.gl_user.identities.find_by(provider: auth_hash.provider)).to be_instance_of Identity + end + it "creates a new user if not found" do expect{ ldap_user.save }.to change{ User.count }.by(1) end diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb index 9c6c3fd8104..e554458e41c 100644 --- a/spec/lib/gitlab/themes_spec.rb +++ b/spec/lib/gitlab/themes_spec.rb @@ -43,9 +43,6 @@ describe Gitlab::Themes do ids = [] described_class.each { |theme| ids << theme.id } expect(ids).not_to be_empty - - # TODO (rspeicher): RSpec 3.x - # expect(described_class.each).to yield_with_arg(described_class::Theme) end end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 9da6c9dc949..8865335d0d1 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -31,13 +31,16 @@ describe NotificationService do describe 'Notes' do context 'issue note' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:empty_project, :private) } let(:issue) { create(:issue, project: project, assignee: create(:user)) } let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } - let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') } + let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') } before do build_team(note.project) + project.team << [issue.author, :master] + project.team << [issue.assignee, :master] + project.team << [note.author, :master] end describe :new_note do @@ -53,6 +56,7 @@ describe NotificationService do should_not_email(@u_participating.id) should_not_email(@u_disabled.id) should_not_email(@unsubscriber.id) + should_not_email(@u_outsider_mentioned) notification.new_note(note) end @@ -444,12 +448,15 @@ describe NotificationService do @u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_MENTION) @u_committer = create(:user, username: 'committer') @u_not_mentioned = create(:user, username: 'regular', notification_level: Notification::N_PARTICIPATING) + @u_outsider_mentioned = create(:user, username: 'outsider') project.team << [@u_watcher, :master] project.team << [@u_participating, :master] + project.team << [@u_participant_mentioned, :master] project.team << [@u_disabled, :master] project.team << [@u_mentioned, :master] project.team << [@u_committer, :master] + project.team << [@u_not_mentioned, :master] end def add_users_with_subscription(project, issuable) |