Commit d866faf2 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into award-emoji-fixes

parents 92af60c2 30ee4ea6
...@@ -28,6 +28,7 @@ v 8.9.0 (unreleased) ...@@ -28,6 +28,7 @@ v 8.9.0 (unreleased)
- Add DB index on users.state - Add DB index on users.state
- Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database - Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
- Changed the Slack build message to use the singular duration if necessary (Aran Koning) - Changed the Slack build message to use the singular duration if necessary (Aran Koning)
- Links from a wiki page to other wiki pages should be rewritten as expected
- Fix issues filter when ordering by milestone - Fix issues filter when ordering by milestone
- Todos will display target state if issuable target is 'Closed' or 'Merged' - Todos will display target state if issuable target is 'Closed' or 'Merged'
- Fix bug when sorting issues by milestone due date and filtering by two or more labels - Fix bug when sorting issues by milestone due date and filtering by two or more labels
...@@ -38,6 +39,7 @@ v 8.9.0 (unreleased) ...@@ -38,6 +39,7 @@ v 8.9.0 (unreleased)
- Use downcased path to container repository as this is expected path by Docker - Use downcased path to container repository as this is expected path by Docker
- Projects pending deletion will render a 404 page - Projects pending deletion will render a 404 page
- Measure queue duration between gitlab-workhorse and Rails - Measure queue duration between gitlab-workhorse and Rails
- Make Omniauth providers specs to not modify global configuration
- Make authentication service for Container Registry to be compatible with < Docker 1.11 - Make authentication service for Container Registry to be compatible with < Docker 1.11
- Add Application Setting to configure Container Registry token expire delay (default 5min) - Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav - Cache assigned issue and merge request counts in sidebar nav
...@@ -65,6 +67,7 @@ v 8.8.4 (unreleased) ...@@ -65,6 +67,7 @@ v 8.8.4 (unreleased)
- Fix importer for GitHub comments on diff - Fix importer for GitHub comments on diff
- Disable Webhooks before proceeding with the GitHub import - Disable Webhooks before proceeding with the GitHub import
- Added descriptions to notification settings dropdown - Added descriptions to notification settings dropdown
- Markdown editor now correctly resets the input value on edit cancellation !4175
v 8.8.3 v 8.8.3
- Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312 - Fix 404 page when viewing TODOs that contain milestones or labels in different projects. !4312
......
...@@ -22,6 +22,24 @@ GitLab.GfmAutoComplete = ...@@ -22,6 +22,24 @@ GitLab.GfmAutoComplete =
Milestones: Milestones:
template: '<li>${title}</li>' template: '<li>${title}</li>'
Loading:
template: '<li><i class="fa fa-refresh fa-spin"></i> Loading...</li>'
DefaultOptions:
sorter: (query, items, searchKey) ->
return items if items[0].name? and items[0].name is 'loading'
$.fn.atwho.default.callbacks.sorter(query, items, searchKey)
filter: (query, data, searchKey) ->
return data if data[0] is 'loading'
$.fn.atwho.default.callbacks.filter(query, data, searchKey)
beforeInsert: (value) ->
if value.indexOf('undefined')
@at
else
value
# Add GFM auto-completion to all input fields, that accept GFM input. # Add GFM auto-completion to all input fields, that accept GFM input.
setup: (wrap) -> setup: (wrap) ->
@input = $('.js-gfm-input') @input = $('.js-gfm-input')
...@@ -53,18 +71,37 @@ GitLab.GfmAutoComplete = ...@@ -53,18 +71,37 @@ GitLab.GfmAutoComplete =
# Emoji # Emoji
@input.atwho @input.atwho
at: ':' at: ':'
displayTpl: @Emoji.template displayTpl: (value) =>
if value.path?
@Emoji.template
else
@Loading.template
insertTpl: ':${name}:' insertTpl: ':${name}:'
data: ['loading']
callbacks:
sorter: @DefaultOptions.sorter
filter: @DefaultOptions.filter
beforeInsert: @DefaultOptions.beforeInsert
# Team Members # Team Members
@input.atwho @input.atwho
at: '@' at: '@'
displayTpl: @Members.template displayTpl: (value) =>
if value.username?
@Members.template
else
@Loading.template
insertTpl: '${atwho-at}${username}' insertTpl: '${atwho-at}${username}'
searchKey: 'search' searchKey: 'search'
data: ['loading']
callbacks: callbacks:
sorter: @DefaultOptions.sorter
filter: @DefaultOptions.filter
beforeInsert: @DefaultOptions.beforeInsert
beforeSave: (members) -> beforeSave: (members) ->
$.map members, (m) -> $.map members, (m) ->
return m if not m.username?
title = m.name title = m.name
title += " (#{m.count})" if m.count title += " (#{m.count})" if m.count
...@@ -76,11 +113,21 @@ GitLab.GfmAutoComplete = ...@@ -76,11 +113,21 @@ GitLab.GfmAutoComplete =
at: '#' at: '#'
alias: 'issues' alias: 'issues'
searchKey: 'search' searchKey: 'search'
displayTpl: @Issues.template displayTpl: (value) =>
if value.title?
@Issues.template
else
@Loading.template
data: ['loading']
insertTpl: '${atwho-at}${id}' insertTpl: '${atwho-at}${id}'
callbacks: callbacks:
sorter: @DefaultOptions.sorter
filter: @DefaultOptions.filter
beforeInsert: @DefaultOptions.beforeInsert
beforeSave: (issues) -> beforeSave: (issues) ->
$.map issues, (i) -> $.map issues, (i) ->
return i if not i.title?
id: i.iid id: i.iid
title: sanitize(i.title) title: sanitize(i.title)
search: "#{i.iid} #{i.title}" search: "#{i.iid} #{i.title}"
...@@ -89,11 +136,18 @@ GitLab.GfmAutoComplete = ...@@ -89,11 +136,18 @@ GitLab.GfmAutoComplete =
at: '%' at: '%'
alias: 'milestones' alias: 'milestones'
searchKey: 'search' searchKey: 'search'
displayTpl: @Milestones.template displayTpl: (value) =>
if value.title?
@Milestones.template
else
@Loading.template
insertTpl: '${atwho-at}"${title}"' insertTpl: '${atwho-at}"${title}"'
data: ['loading']
callbacks: callbacks:
beforeSave: (milestones) -> beforeSave: (milestones) ->
$.map milestones, (m) -> $.map milestones, (m) ->
return m if not m.title?
id: m.iid id: m.iid
title: sanitize(m.title) title: sanitize(m.title)
search: "#{m.title}" search: "#{m.title}"
...@@ -102,11 +156,21 @@ GitLab.GfmAutoComplete = ...@@ -102,11 +156,21 @@ GitLab.GfmAutoComplete =
at: '!' at: '!'
alias: 'mergerequests' alias: 'mergerequests'
searchKey: 'search' searchKey: 'search'
displayTpl: @Issues.template displayTpl: (value) =>
if value.title?
@Issues.template
else
@Loading.template
data: ['loading']
insertTpl: '${atwho-at}${id}' insertTpl: '${atwho-at}${id}'
callbacks: callbacks:
sorter: @DefaultOptions.sorter
filter: @DefaultOptions.filter
beforeInsert: @DefaultOptions.beforeInsert
beforeSave: (merges) -> beforeSave: (merges) ->
$.map merges, (m) -> $.map merges, (m) ->
return m if not m.title?
id: m.iid id: m.iid
title: sanitize(m.title) title: sanitize(m.title)
search: "#{m.iid} #{m.title}" search: "#{m.iid} #{m.title}"
...@@ -128,3 +192,7 @@ GitLab.GfmAutoComplete = ...@@ -128,3 +192,7 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', 'mergerequests', data.mergerequests @input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis # load emojis
@input.atwho 'load', ':', data.emojis @input.atwho 'load', ':', data.emojis
# This trigger at.js again
# otherwise we would be stuck with loading until the user types
$(':focus').trigger('keyup')
...@@ -354,8 +354,7 @@ class @Notes ...@@ -354,8 +354,7 @@ class @Notes
Called in response to clicking the edit note link Called in response to clicking the edit note link
Replaces the note text with the note edit form Replaces the note text with the note edit form
Adds a hidden div with the original content of the note to fill the edit note form with Adds a data attribute to the form with the original content of the note for cancellations
if the user cancels
### ###
showEditForm: (e, scrollTo, myLastNote) -> showEditForm: (e, scrollTo, myLastNote) ->
e.preventDefault() e.preventDefault()
...@@ -371,6 +370,8 @@ class @Notes ...@@ -371,6 +370,8 @@ class @Notes
done = ($noteText) -> done = ($noteText) ->
# Neat little trick to put the cursor at the end # Neat little trick to put the cursor at the end
noteTextVal = $noteText.val() noteTextVal = $noteText.val()
# Store the original note text in a data attribute to retrieve if a user cancels edit.
form.find('form.edit-note').data 'original-note', noteTextVal
$noteText.val('').val(noteTextVal); $noteText.val('').val(noteTextVal);
new GLForm form new GLForm form
...@@ -393,14 +394,16 @@ class @Notes ...@@ -393,14 +394,16 @@ class @Notes
### ###
Called in response to clicking the edit note link Called in response to clicking the edit note link
Hides edit form Hides edit form and restores the original note text to the editor textarea.
### ###
cancelEdit: (e) -> cancelEdit: (e) ->
e.preventDefault() e.preventDefault()
note = $(this).closest(".note") note = $(this).closest(".note")
form = note.find(".current-note-edit-form")
note.removeClass "is-editting" note.removeClass "is-editting"
note.find(".current-note-edit-form") form.removeClass("current-note-edit-form")
.removeClass("current-note-edit-form") # Replace markdown textarea text with original note text.
form.find(".js-note-text").val(form.find('form.edit-note').data('original-note'))
### ###
Called in response to deleting a note of any kind. Called in response to deleting a note of any kind.
......
...@@ -38,6 +38,11 @@ ...@@ -38,6 +38,11 @@
.header-logo { .header-logo {
height: $header-height; height: $header-height;
padding: 8px 26px; padding: 8px 26px;
width: $sidebar_width;
position: fixed;
z-index: 999;
overflow: hidden;
transition-duration: .3s;
&:hover { &:hover {
background-color: #eee; background-color: #eee;
...@@ -73,7 +78,8 @@ ...@@ -73,7 +78,8 @@
.nav-sidebar { .nav-sidebar {
margin: 22px 0; margin-top: 22 + $header-height;
margin-bottom: 116px;
transition-duration: .3s; transition-duration: .3s;
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
...@@ -166,6 +172,7 @@ ...@@ -166,6 +172,7 @@
.header-logo { .header-logo {
width: 0; width: 0;
padding: 8px 0;
a { a {
padding-left: ($sidebar_collapsed_width - 36) / 2; padding-left: ($sidebar_collapsed_width - 36) / 2;
......
class Projects::GitHttpController < Projects::ApplicationController class Projects::GitHttpController < Projects::ApplicationController
attr_reader :user attr_reader :user
# Git clients will not know what authenticity token to send along
skip_before_action :verify_authenticity_token
skip_before_action :repository skip_before_action :repository
before_action :authenticate_user before_action :authenticate_user
before_action :ensure_project_found! before_action :ensure_project_found!
......
...@@ -95,7 +95,7 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -95,7 +95,7 @@ class Projects::WikisController < Projects::ApplicationController
ext.analyze(text, author: current_user) ext.analyze(text, author: current_user)
render json: { render json: {
body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki), body: view_context.markdown(text, pipeline: :wiki, project_wiki: @project_wiki, page_slug: params[:id]),
references: { references: {
users: ext.users.map(&:username) users: ext.users.map(&:username)
} }
......
...@@ -108,7 +108,7 @@ module GitlabMarkdownHelper ...@@ -108,7 +108,7 @@ module GitlabMarkdownHelper
def render_wiki_content(wiki_page) def render_wiki_content(wiki_page)
case wiki_page.format case wiki_page.format
when :markdown when :markdown
markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki) markdown(wiki_page.content, pipeline: :wiki, project_wiki: @project_wiki, page_slug: wiki_page.slug)
when :asciidoc when :asciidoc
asciidoc(wiki_page.content) asciidoc(wiki_page.content)
else else
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
- content_for :scripts_body_top do - content_for :scripts_body_top do
- project = @target_project || @project - project = @target_project || @project
- if @project_wiki - if @project_wiki && @page
- markdown_preview_path = namespace_project_wikis_markdown_preview_path(project.namespace, project) - markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, params[:id])
- else - else
- markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project) - markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project)
- if current_user - if current_user
......
...@@ -20,10 +20,11 @@ ...@@ -20,10 +20,11 @@
- access = note.project.team.human_max_access(note.author.id) - access = note.project.team.human_max_access(note.author.id)
- if access - if access
%span.note-role.hidden-xs= access %span.note-role.hidden-xs= access
- if note_editable - if current_user
= link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do
= icon('spinner spin') = icon('spinner spin')
= icon('smile-o') = icon('smile-o')
- if note_editable
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do
= icon('pencil') = icon('pencil')
= link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do
......
...@@ -616,7 +616,6 @@ Rails.application.routes.draw do ...@@ -616,7 +616,6 @@ Rails.application.routes.draw do
# Order matters to give priority to these matches # Order matters to give priority to these matches
get '/wikis/git_access', to: 'wikis#git_access' get '/wikis/git_access', to: 'wikis#git_access'
get '/wikis/pages', to: 'wikis#pages', as: 'wiki_pages' get '/wikis/pages', to: 'wikis#pages', as: 'wiki_pages'
post '/wikis/markdown_preview', to:'wikis#markdown_preview'
post '/wikis', to: 'wikis#create' post '/wikis', to: 'wikis#create'
get '/wikis/*id/history', to: 'wikis#history', as: 'wiki_history', constraints: WIKI_SLUG_ID get '/wikis/*id/history', to: 'wikis#history', as: 'wiki_history', constraints: WIKI_SLUG_ID
...@@ -625,6 +624,7 @@ Rails.application.routes.draw do ...@@ -625,6 +624,7 @@ Rails.application.routes.draw do
get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID
delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID
put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID
post '/wikis/*id/markdown_preview', to:'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview'
end end
resource :repository, only: [:show, :create] do resource :repository, only: [:show, :create] do
......
...@@ -97,7 +97,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps ...@@ -97,7 +97,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
file = Gollum::File.new(wiki.wiki) file = Gollum::File.new(wiki.wiki)
Gollum::Wiki.any_instance.stub(:file).with("image.jpg", "master", true).and_return(file) Gollum::Wiki.any_instance.stub(:file).with("image.jpg", "master", true).and_return(file)
Gollum::File.any_instance.stub(:mime_type).and_return("image/jpeg") Gollum::File.any_instance.stub(:mime_type).and_return("image/jpeg")
expect(page).to have_link('image', href: "image.jpg") expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/image.jpg")
click_on "image" click_on "image"
end end
...@@ -113,7 +113,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps ...@@ -113,7 +113,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end end
step 'I click on image link' do step 'I click on image link' do
expect(page).to have_link('image', href: "image.jpg") expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/image.jpg")
click_on "image" click_on "image"
end end
......
...@@ -2,7 +2,8 @@ require 'uri' ...@@ -2,7 +2,8 @@ require 'uri'
module Banzai module Banzai
module Filter module Filter
# HTML filter that "fixes" relative links to files in a repository. # HTML filter that "fixes" links to pages/files in a wiki.
# Rewrite rules are documented in the `WikiPipeline` spec.
# #
# Context options: # Context options:
# :project_wiki # :project_wiki
...@@ -25,36 +26,15 @@ module Banzai ...@@ -25,36 +26,15 @@ module Banzai
end end
def process_link_attr(html_attr) def process_link_attr(html_attr)
return if html_attr.blank? || file_reference?(html_attr) || hierarchical_link?(html_attr) return if html_attr.blank?
uri = URI(html_attr.value) html_attr.value = apply_rewrite_rules(html_attr.value)
if uri.relative? && uri.path.present?
html_attr.value = rebuild_wiki_uri(uri).to_s
end
rescue URI::Error rescue URI::Error
# noop # noop
end end
def rebuild_wiki_uri(uri) def apply_rewrite_rules(link_string)
uri.path = ::File.join(project_wiki_base_path, uri.path) Rewriter.new(link_string, wiki: context[:project_wiki], slug: context[:page_slug]).apply_rules
uri
end
def project_wiki
context[:project_wiki]
end
def file_reference?(html_attr)
!File.extname(html_attr.value).blank?
end
# Of the form `./link`, `../link`, or similar
def hierarchical_link?(html_attr)
html_attr.value[0] == '.'
end
def project_wiki_base_path
project_wiki && project_wiki.wiki_base_path
end end
end end
end end
......
module Banzai
module Filter
class WikiLinkFilter < HTML::Pipeline::Filter
class Rewriter
def initialize(link_string, wiki:, slug:)
@uri = Addressable::URI.parse(link_string)
@wiki_base_path = wiki && wiki.wiki_base_path
@slug = slug
end
def apply_rules
apply_file_link_rules!
apply_hierarchical_link_rules!
apply_relative_link_rules!
@uri.to_s
end
private
# Of the form 'file.md'
def apply_file_link_rules!
@uri = Addressable::URI.join(@slug, @uri) if @uri.extname.present?
end
# Of the form `./link`, `../link`, or similar
def apply_hierarchical_link_rules!
@uri = Addressable::URI.join(@slug, @uri) if @uri.to_s[0] == '.'
end
# Any link _not_ of the form `http://example.com/`
def apply_relative_link_rules!
if @uri.relative? && @uri.path.present?
link = ::File.join(@wiki_base_path, @uri.path)
@uri = Addressable::URI.parse(link)
end
end
end
end
end
end
...@@ -69,13 +69,20 @@ module Gitlab ...@@ -69,13 +69,20 @@ module Gitlab
return unless ldap_person return unless ldap_person
# If a corresponding person exists with same uid in a LDAP server, # If a corresponding person exists with same uid in a LDAP server,
# set up a Gitlab user with dual LDAP and Omniauth identities. # check if the user already has a GitLab account.
if user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider) user = Gitlab::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider)
# Case when a LDAP user already exists in Gitlab. Add the Omniauth identity to existing account. if user
# Case when a LDAP user already exists in Gitlab. Add the OAuth identity to existing account.
log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity."
user.identities.build(extern_uid: auth_hash.uid, provider: auth_hash.provider) user.identities.build(extern_uid: auth_hash.uid, provider: auth_hash.provider)
else else
# No account in Gitlab yet: create it and add the LDAP identity log.info "No existing LDAP account was found in GitLab. Checking for #{auth_hash.provider} account."
user = build_new_user user = find_by_uid_and_provider
if user.nil?
log.info "No user found using #{auth_hash.provider} provider. Creating a new one."
user = build_new_user
end
log.info "Correct account has been found. Adding LDAP identity to user: #{user.username}."
user.identities.new(provider: ldap_person.provider, extern_uid: ldap_person.dn) user.identities.new(provider: ldap_person.provider, extern_uid: ldap_person.dn)
end end
......
...@@ -12,12 +12,12 @@ module Gitlab ...@@ -12,12 +12,12 @@ module Gitlab
end end
def gl_user def gl_user
@user ||= find_by_uid_and_provider
if auto_link_ldap_user? if auto_link_ldap_user?
@user ||= find_or_create_ldap_user @user ||= find_or_create_ldap_user
end end
@user ||= find_by_uid_and_provider
if auto_link_saml_user? if auto_link_saml_user?
@user ||= find_by_email @user ||= find_by_email
end end
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::BitbucketController do describe Import::BitbucketController do
include ImportSpecHelper include ImportSpecHelper
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::FogbugzController do describe Import::FogbugzController do
include ImportSpecHelper include ImportSpecHelper
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::GithubController do describe Import::GithubController do
include ImportSpecHelper include ImportSpecHelper
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::GitlabController do describe Import::GitlabController do
include ImportSpecHelper include ImportSpecHelper
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::GitoriousController do describe Import::GitoriousController do
include ImportSpecHelper include ImportSpecHelper
......
require 'spec_helper' require 'spec_helper'
require_relative 'import_spec_helper'
describe Import::GoogleCodeController do describe Import::GoogleCodeController do
include ImportSpecHelper include ImportSpecHelper
......
...@@ -2,7 +2,7 @@ require 'ostruct' ...@@ -2,7 +2,7 @@ require 'ostruct'
FactoryGirl.define do FactoryGirl.define do
factory :wiki_page do factory :wiki_page do
page = OpenStruct.new(url_path: 'some-name') page { OpenStruct.new(url_path: 'some-name') }
association :wiki, factory: :project_wiki, strategy: :build association :wiki, factory: :project_wiki, strategy: :build
initialize_with { new(wiki, page, true) } initialize_with { new(wiki, page, true) }
end end
......
...@@ -241,13 +241,14 @@ describe 'GitLab Markdown', feature: true do ...@@ -241,13 +241,14 @@ describe 'GitLab Markdown', feature: true do
context 'wiki pipeline' do context 'wiki pipeline' do
before do before do
@project_wiki = @feat.project_wiki @project_wiki = @feat.project_wiki
@project_wiki_page = @feat.project_wiki_page
file = Gollum::File.new(@project_wiki.wiki) file = Gollum::File.new(@project_wiki.wiki)
expect(file).to receive(:path).and_return('images/example.jpg') expect(file).to receive(:path).and_return('images/example.jpg')
expect(@project_wiki).to receive(:find_file).with('images/example.jpg').and_return(file) expect(@project_wiki).to receive(:find_file).with('images/example.jpg').and_return(file)
allow(@project_wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' } allow(@project_wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
@html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki }) @html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki, page_slug: @project_wiki_page.slug })
end end
it_behaves_like 'all pipelines' it_behaves_like 'all pipelines'
......
...@@ -121,13 +121,14 @@ describe GitlabMarkdownHelper do ...@@ -121,13 +121,14 @@ describe GitlabMarkdownHelper do
before do before do
@wiki = double('WikiPage') @wiki = double('WikiPage')
allow(@wiki).to receive(:content).and_return('wiki content') allow(@wiki).to receive(:content).and_return('wiki content')
allow(@wiki).to receive(:slug).and_return('nested/page')
helper.instance_variable_set(:@project_wiki, @wiki) helper.instance_variable_set(:@project_wiki, @wiki)
end end
it "should use Wiki pipeline for markdown files" do it "should use Wiki pipeline for markdown files" do
allow(@wiki).to receive(:format).and_return(:markdown) allow(@wiki).to receive(:format).and_return(:markdown)
expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki) expect(helper).to receive(:markdown).with('wiki content', pipeline: :wiki, project_wiki: @wiki, page_slug: "nested/page")
helper.render_wiki_content(@wiki) helper.render_wiki_content(@wiki)
end end
......
require 'spec_helper'
describe Banzai::Filter::WikiLinkFilter, lib: true do
include FilterSpecHelper
let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
let(:project) { build_stubbed(:empty_project, :public, name: "wiki_link_project", namespace: namespace) }
let(:user) { double }
let(:project_wiki) { ProjectWiki.new(project, user) }
describe "links within the wiki (relative)" do
describe "hierarchical links to the current directory" do
it "doesn't rewrite non-file links" do
link = "<a href='./page'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('./page')
end
it "doesn't rewrite file links" do
link = "<a href='./page.md'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('./page.md')
end
end
describe "hierarchical links to the parent directory" do
it "doesn't rewrite non-file links" do
link = "<a href='../page'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('../page')
end
it "doesn't rewrite file links" do
link = "<a href='../page.md'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('../page.md')
end
end
describe "hierarchical links to a sub-directory" do
it "doesn't rewrite non-file links" do
link = "<a href='./subdirectory/page'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('./subdirectory/page')
end
it "doesn't rewrite file links" do
link = "<a href='./subdirectory/page.md'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('./subdirectory/page.md')
end
end
describe "non-hierarchical links" do
it 'rewrites non-file links to be at the scope of the wiki root' do
link = "<a href='page'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to match('/wiki_link_ns/wiki_link_project/wikis/page')
end
it "doesn't rewrite file links" do
link = "<a href='page.md'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('page.md')
end
end
end
describe "links outside the wiki (absolute)" do
it "doesn't rewrite links" do
link = "<a href='http://example.com/page'>Link to Page</a>"
filtered_link = filter(link, project_wiki: project_wiki).children[0]
expect(filtered_link.attribute('href').value).to eq('http://example.com/page')
end
end
end
...@@ -50,4 +50,112 @@ describe Banzai::Pipeline::WikiPipeline do ...@@ -50,4 +50,112 @@ describe Banzai::Pipeline::WikiPipeline do
end end
end end
end end
describe "Links" do
let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") }
let(:project) { build_stubbed(:empty_project, :public, name: "wiki_link_project", namespace: namespace) }
let(:project_wiki) { ProjectWiki.new(project, double(:user)) }
let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) }
{ "when GitLab is hosted at a root URL" => '/',
"when GitLab is hosted at a relative URL" => '/nested/relative/gitlab' }.each do |test_name, relative_url_root|
context test_name do
before do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return(relative_url_root)
end
describe "linking to pages within the wiki" do
context "when creating hierarchical links to the current directory" do
it "rewrites non-file links to be at the scope of the current directory" do
markdown = "[Page](./page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page\"")
end
it "rewrites file links to be at the scope of the current directory" do
markdown = "[Link to Page](./page.md)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end
end
context "when creating hierarchical links to the parent directory" do
it "rewrites non-file links to be at the scope of the parent directory" do
markdown = "[Link to Page](../page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page\"")
end
it "rewrites file links to be at the scope of the parent directory" do
markdown = "[Link to Page](../page.md)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/page.md\"")
end
end
context "when creating hierarchical links to a sub-directory" do
it "rewrites non-file links to be at the scope of the sub-directory" do
markdown = "[Link to Page](./subdirectory/page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page\"")
end
it "rewrites file links to be at the scope of the sub-directory" do
markdown = "[Link to Page](./subdirectory/page.md)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/subdirectory/page.md\"")
end
end
describe "when creating non-hierarchical links" do
it 'rewrites non-file links to be at the scope of the wiki root' do
markdown = "[Link to Page](page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
end
it "rewrites file links to be at the scope of the current directory" do
markdown = "[Link to Page](page.md)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end
end
describe "when creating root links" do
it 'rewrites non-file links to be at the scope of the wiki root' do
markdown = "[Link to Page](/page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page\"")
end
it 'rewrites file links to be at the scope of the wiki root' do
markdown = "[Link to Page](/page.md)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/page.md\"")
end
end
end
describe "linking to pages outside the wiki (absolute)" do
it "doesn't rewrite links" do
markdown = "[Link to Page](http://example.com/page)"
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include('href="http://example.com/page"')
end
end
end
end
end
end end
require 'spec_helper' require 'spec_helper'
describe Gitlab::BitbucketImport::Client, lib: true do describe Gitlab::BitbucketImport::Client, lib: true do
include ImportSpecHelper
let(:token) { '123456' } let(:token) { '123456' }
let(:secret) { 'secret' } let(:secret) { 'secret' }
let(:client) { Gitlab::BitbucketImport::Client.new(token, secret) } let(:client) { Gitlab::BitbucketImport::Client.new(token, secret) }
before do before do
Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "bitbucket") stub_omniauth_provider('bitbucket')
end end
it 'all OAuth client options are symbols' do it 'all OAuth client options are symbols' do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::BitbucketImport::Importer, lib: true do describe Gitlab::BitbucketImport::Importer, lib: true do
include ImportSpecHelper
before do before do
Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "bitbucket") stub_omniauth_provider('bitbucket')
end end
let(:statuses) do let(:statuses) do
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::GitlabImport::Client, lib: true do describe Gitlab::GitlabImport::Client, lib: true do
include ImportSpecHelper
let(:token) { '123456' } let(:token) { '123456' }
let(:client) { Gitlab::GitlabImport::Client.new(token) } let(:client) { Gitlab::GitlabImport::Client.new(token) }
before do before do
Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "gitlab") stub_omniauth_provider('gitlab')
end end
it 'all OAuth2 client options are symbols' do it 'all OAuth2 client options are symbols' do
......
...@@ -145,6 +145,7 @@ describe Gitlab::Saml::User, lib: true do ...@@ -145,6 +145,7 @@ describe Gitlab::Saml::User, lib: true do
allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) } allow(ldap_user).to receive(:email) { %w(john@mail.com john2@example.com) }
allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' } allow(ldap_user).to receive(:dn) { 'uid=user1,ou=People,dc=example' }
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user) allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
allow(Gitlab::LDAP::Person).to receive(:find_by_dn).and_return(ldap_user)
end end
context 'and no account for the LDAP user' do context 'and no account for the LDAP user' do
...@@ -177,6 +178,23 @@ describe Gitlab::Saml::User, lib: true do ...@@ -177,6 +178,23 @@ describe Gitlab::Saml::User, lib: true do
]) ])
end end
end end
context 'user has SAML user, and wants to add their LDAP identity' do
it 'adds the LDAP identity to the existing SAML user' do
create(:omniauth_user, email: 'john@mail.com', extern_uid: 'uid=user1,ou=People,dc=example', provider: 'saml', username: 'john')
local_hash = OmniAuth::AuthHash.new(uid: 'uid=user1,ou=People,dc=example', provider: provider, info: info_hash)
local_saml_user = described_class.new(local_hash)
local_saml_user.save
local_gl_user = local_saml_user.gl_user
expect(local_gl_user).to be_valid
expect(local_gl_user.identities.length).to eql 2
identities_as_hash = local_gl_user.identities.map { |id| { provider: id.provider, extern_uid: id.extern_uid } }
expect(identities_as_hash).to match_array([ { provider: 'ldapmain', extern_uid: 'uid=user1,ou=People,dc=example' },
{ provider: 'saml', extern_uid: 'uid=user1,ou=People,dc=example' }
])
end
end
end end
end end
end end
......
...@@ -124,7 +124,7 @@ describe Projects::ImportService, services: true do ...@@ -124,7 +124,7 @@ describe Projects::ImportService, services: true do
} }
) )
Gitlab.config.omniauth.providers << provider allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
end end
end end
end end
...@@ -28,6 +28,6 @@ module ImportSpecHelper ...@@ -28,6 +28,6 @@ module ImportSpecHelper
app_id: 'asd123', app_id: 'asd123',
app_secret: 'asd123' app_secret: 'asd123'
) )
Gitlab.config.omniauth.providers << provider allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider])
end end
end end
...@@ -32,6 +32,10 @@ class MarkdownFeature ...@@ -32,6 +32,10 @@ class MarkdownFeature
@project_wiki ||= ProjectWiki.new(project, user) @project_wiki ||= ProjectWiki.new(project, user)
end end
def project_wiki_page
@project_wiki_page ||= build(:wiki_page, wiki: project_wiki)
end
def issue def issue
@issue ||= create(:issue, project: project) @issue ||= create(:issue, project: project)
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