summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG4
-rw-r--r--app/assets/javascripts/user_tabs.js.coffee9
-rw-r--r--app/controllers/projects/hooks_controller.rb6
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/users_controller.rb22
-rw-r--r--app/helpers/events_helper.rb9
-rw-r--r--app/models/hooks/web_hook.rb2
-rw-r--r--app/views/layouts/header/_default.html.haml5
-rw-r--r--app/views/users/show.html.haml6
-rw-r--r--config/routes.rb32
-rw-r--r--doc/web_hooks/web_hooks.md13
-rw-r--r--features/steps/project/hooks.rb2
-rw-r--r--lib/banzai/filter/wiki_link_filter.rb11
-rw-r--r--spec/controllers/users_controller_spec.rb22
-rw-r--r--spec/lib/banzai/filter/wiki_link_filter_spec.rb85
-rw-r--r--spec/models/hooks/web_hook_spec.rb4
-rw-r--r--spec/routing/routing_spec.rb41
17 files changed, 231 insertions, 44 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 4841361482d..187011c6016 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.8.0 (unreleased)
+ - Snippets tab under user profile. !4001 (Long Nguyen)
- Fix error when using link to uploads in global snippets
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Use a case-insensitive comparison in sanitizing URI schemes
@@ -43,6 +44,9 @@ v 8.8.0 (unreleased)
- Fix adding a todo for private group members (Ahmad Sherif)
- Bump ace-rails-ap gem version from 2.0.1 to 4.0.2 which upgrades Ace Editor from 1.1.2 to 1.2.3
+v 8.7.5
+ - Fix relative links in wiki pages. !4050
+
v 8.7.4
- Links for Redmine issue references are generated correctly again !4048 (Benedikt Huss)
- Fix setting trusted proxies !3970
diff --git a/app/assets/javascripts/user_tabs.js.coffee b/app/assets/javascripts/user_tabs.js.coffee
index c2aeffe2381..70614396a4e 100644
--- a/app/assets/javascripts/user_tabs.js.coffee
+++ b/app/assets/javascripts/user_tabs.js.coffee
@@ -26,6 +26,10 @@
# Personal projects
# </a>
# </li>
+# <li class="snippets-tab">
+# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
+# </a>
+# </li>
# </ul>
#
# <div class="tab-content">
@@ -41,6 +45,9 @@
# <div class="tab-pane" id="projects">
# Projects content
# </div>
+# <div class="tab-pane" id="snippets">
+# Snippets content
+# </div>
# </div>
#
# <div class="loading-status">
@@ -100,7 +107,7 @@ class @UserTabs
if action is 'activity'
@loadActivities(source)
- if action in ['groups', 'contributed', 'projects']
+ if action in ['groups', 'contributed', 'projects', 'snippets']
@loadTab(source, action)
loadTab: (source, action) ->
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index dfa9bd259e8..47524b1cf0b 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -27,8 +27,10 @@ class Projects::HooksController < Projects::ApplicationController
if !@project.empty_repo?
status, message = TestHookService.new.execute(hook, current_user)
- if status
- flash[:notice] = 'Hook successfully executed.'
+ if status && status >= 200 && status < 400
+ flash[:notice] = "Hook executed successfully: HTTP #{status}"
+ elsif status
+ flash[:alert] = "Hook executed successfully but returned HTTP #{status} #{message}"
else
flash[:alert] = "Hook execution failed: #{message}"
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 2daceed039b..2a17c1f34db 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -10,7 +10,7 @@ class SnippetsController < ApplicationController
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
- skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw]
+ skip_before_action :authenticate_user!, only: [:index, :show, :raw]
layout 'snippets'
respond_to :html
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 2ae180c8a12..799421c185b 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -58,6 +58,19 @@ class UsersController < ApplicationController
end
end
+ def snippets
+ load_snippets
+
+ respond_to do |format|
+ format.html { render 'show' }
+ format.json do
+ render json: {
+ html: view_to_html_string("snippets/_snippets", collection: @snippets)
+ }
+ end
+ end
+ end
+
def calendar
calendar = contributions_calendar
@timestamps = calendar.timestamps
@@ -116,6 +129,15 @@ class UsersController < ApplicationController
@groups = JoinedGroupsFinder.new(user).execute(current_user)
end
+ def load_snippets
+ @snippets = SnippetsFinder.new.execute(
+ current_user,
+ filter: :by_user,
+ user: user,
+ scope: params[:scope]
+ ).page(params[:page])
+ end
+
def projects_for_current_user
ProjectsFinder.new.execute(current_user)
end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index 592bad8ba24..0bf328e7d19 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -39,15 +39,6 @@ module EventsHelper
end
end
- def icon_for_event
- {
- EventFilter.push => 'upload',
- EventFilter.merged => 'check-square-o',
- EventFilter.comments => 'comments',
- EventFilter.team => 'user',
- }
- end
-
def event_preposition(event)
if event.push? || event.commented? || event.target
"at"
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index fde05f729dc..8b87b6c3d64 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -38,7 +38,7 @@ class WebHook < ActiveRecord::Base
basic_auth: auth)
end
- [(response.code >= 200 && response.code < 300), ActionView::Base.full_sanitizer.sanitize(response.to_s)]
+ [response.code, response.to_s]
rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e
logger.error("WebHook Error => #{e}")
[false, e.to_s]
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index 172579dafda..c33740e23fa 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -27,8 +27,9 @@
%li
= link_to dashboard_todos_path, title: 'Todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('bell fw')
- %span.badge.todos-pending-count
- = todos_pending_count
+ - unless todos_pending_count == 0
+ %span.badge.todos-pending-count
+ = todos_pending_count
- if current_user.can_create_project?
%li
= link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 3c0b89c6741..9017fd54fcc 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -81,6 +81,9 @@
%li.projects-tab
= link_to user_projects_path, data: {target: 'div#projects', action: 'projects', toggle: 'tab'} do
Personal projects
+ %li.snippets-tab
+ = link_to user_snippets_path, data: {target: 'div#snippets', action: 'snippets', toggle: 'tab'} do
+ Snippets
%div{ class: container_class }
.tab-content
@@ -104,6 +107,9 @@
#projects.tab-pane
- # This tab is always loaded via AJAX
+ #snippets.tab-pane
+ - # This tab is always loaded via AJAX
+
.loading-status
= spinner
diff --git a/config/routes.rb b/config/routes.rb
index dafecc94648..881de37f10e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -91,7 +91,8 @@ Rails.application.routes.draw do
end
end
- get '/s/:username' => 'snippets#index', as: :user_snippets, constraints: { username: /.*/ }
+ get '/s/:username', to: redirect('/u/%{username}/snippets'),
+ constraints: { username: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }
#
# Invites
@@ -342,23 +343,18 @@ Rails.application.routes.draw do
end
end
- get 'u/:username/calendar' => 'users#calendar', as: :user_calendar,
- constraints: { username: /.*/ }
-
- get 'u/:username/calendar_activities' => 'users#calendar_activities', as: :user_calendar_activities,
- constraints: { username: /.*/ }
-
- get 'u/:username/groups' => 'users#groups', as: :user_groups,
- constraints: { username: /.*/ }
-
- get 'u/:username/projects' => 'users#projects', as: :user_projects,
- constraints: { username: /.*/ }
-
- get 'u/:username/contributed' => 'users#contributed', as: :user_contributed_projects,
- constraints: { username: /.*/ }
-
- get '/u/:username' => 'users#show', as: :user,
- constraints: { username: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }
+ scope(path: 'u/:username',
+ as: :user,
+ constraints: { username: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ },
+ controller: :users) do
+ get :calendar
+ get :calendar_activities
+ get :groups
+ get :projects
+ get :contributed, as: :contributed_projects
+ get :snippets
+ get '/', action: :show
+ end
#
# Dashboard Area
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index c1c51302e79..45506ac1d7c 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -13,6 +13,19 @@ You can configure webhooks to listen for specific events like pushes, issues or
Webhooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
+## Webhook endpoint tips
+
+If you are writing your own endpoint (web server) that will receive
+GitLab webhooks keep in mind the following things:
+
+- Your endpoint should send its HTTP response as fast as possible. If
+ you wait too long, GitLab may decide the hook failed and retry it.
+- Your endpoint should ALWAYS return a valid HTTP response. If you do
+ not do this then GitLab will think the hook failed and retry it.
+ Most HTTP libraries take care of this for you automatically but if
+ you are writing a low-level hook this is important to remember.
+- GitLab ignores the HTTP status code returned by your endpoint.
+
## SSL Verification
By default, the SSL certificate of the webhook endpoint is verified based on
diff --git a/features/steps/project/hooks.rb b/features/steps/project/hooks.rb
index b1ffe7f7b4c..13c0713669a 100644
--- a/features/steps/project/hooks.rb
+++ b/features/steps/project/hooks.rb
@@ -59,7 +59,7 @@ class Spinach::Features::ProjectHooks < Spinach::FeatureSteps
step 'hook should be triggered' do
expect(current_path).to eq namespace_project_hooks_path(current_project.namespace, current_project)
expect(page).to have_selector '.flash-notice',
- text: 'Hook successfully executed.'
+ text: 'Hook executed successfully: HTTP 200'
end
step 'I should see hook error message' do
diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb
index 06d10c98501..7dc771afd71 100644
--- a/lib/banzai/filter/wiki_link_filter.rb
+++ b/lib/banzai/filter/wiki_link_filter.rb
@@ -25,7 +25,7 @@ module Banzai
end
def process_link_attr(html_attr)
- return if html_attr.blank? || file_reference?(html_attr)
+ return if html_attr.blank? || file_reference?(html_attr) || hierarchical_link?(html_attr)
uri = URI(html_attr.value)
if uri.relative? && uri.path.present?
@@ -40,12 +40,17 @@ module Banzai
uri
end
+ def project_wiki
+ context[:project_wiki]
+ end
+
def file_reference?(html_attr)
!File.extname(html_attr.value).blank?
end
- def project_wiki
- context[:project_wiki]
+ # Of the form `./link`, `../link`, or similar
+ def hierarchical_link?(html_attr)
+ html_attr.value[0] == '.'
end
def project_wiki_base_path
diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb
index 8045c8b940d..c61ec174665 100644
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -112,4 +112,26 @@ describe UsersController do
expect(response).to render_template('calendar_activities')
end
end
+
+ describe 'GET #snippets' do
+ before do
+ sign_in(user)
+ end
+
+ context 'format html' do
+ it 'renders snippets page' do
+ get :snippets, username: user.username
+ expect(response.status).to eq(200)
+ expect(response).to render_template('show')
+ end
+ end
+
+ context 'format json' do
+ it 'response with snippets json data' do
+ get :snippets, username: user.username, format: :json
+ expect(response.status).to eq(200)
+ expect(JSON.parse(response.body)).to have_key('html')
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
new file mode 100644
index 00000000000..185abbb2108
--- /dev/null
+++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb
@@ -0,0 +1,85 @@
+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
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 37a27d73aab..f9bab487b96 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -95,13 +95,13 @@ describe WebHook, models: true do
it "handles 200 status code" do
WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "Success")
- expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success'])
+ expect(project_hook.execute(@data, 'push_hooks')).to eq([200, 'Success'])
end
it "handles 2xx status codes" do
WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: "Success")
- expect(project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success'])
+ expect(project_hook.execute(@data, 'push_hooks')).to eq([201, 'Success'])
end
end
end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 1527eddfa48..8530a2f31d5 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -1,5 +1,42 @@
require 'spec_helper'
+# user GET /u/:username/
+# user_groups GET /u/:username/groups(.:format)
+# user_projects GET /u/:username/projects(.:format)
+# user_contributed_projects GET /u/:username/contributed(.:format)
+# user_snippets GET /u/:username/snippets(.:format)
+# user_calendar GET /u/:username/calendar(.:format)
+# user_calendar_activities GET /u/:username/calendar_activities(.:format)
+describe UsersController, "routing" do
+ it "to #show" do
+ expect(get("/u/User")).to route_to('users#show', username: 'User')
+ end
+
+ it "to #groups" do
+ expect(get("/u/User/groups")).to route_to('users#groups', username: 'User')
+ end
+
+ it "to #projects" do
+ expect(get("/u/User/projects")).to route_to('users#projects', username: 'User')
+ end
+
+ it "to #contributed" do
+ expect(get("/u/User/contributed")).to route_to('users#contributed', username: 'User')
+ end
+
+ it "to #snippets" do
+ expect(get("/u/User/snippets")).to route_to('users#snippets', username: 'User')
+ end
+
+ it "to #calendar" do
+ expect(get("/u/User/calendar")).to route_to('users#calendar', username: 'User')
+ end
+
+ it "to #calendar_activities" do
+ expect(get("/u/User/calendar_activities")).to route_to('users#calendar_activities', username: 'User')
+ end
+end
+
# search GET /search(.:format) search#show
describe SearchController, "routing" do
it "to #show" do
@@ -27,10 +64,6 @@ end
# PUT /snippets/:id(.:format) snippets#update
# DELETE /snippets/:id(.:format) snippets#destroy
describe SnippetsController, "routing" do
- it "to #user_index" do
- expect(get("/s/User")).to route_to('snippets#index', username: 'User')
- end
-
it "to #raw" do
expect(get("/snippets/1/raw")).to route_to('snippets#raw', id: '1')
end