Commit c754a8e9 authored by Markus Koller's avatar Markus Koller Committed by Stan Hu

Add group wiki controller

- Introduces `Groups::WikisController` and corresponding routes.
- Refactors shared examples for resource routing.
- Tweaks `Gitlab::UrlBuilder` to use the new routes.
parent 58e88479
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
module WikiActions module WikiActions
include DiffHelper include DiffHelper
include PreviewMarkdown
include SendsBlob include SendsBlob
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
extend ActiveSupport::Concern extend ActiveSupport::Concern
......
...@@ -81,10 +81,6 @@ class Projects::ApplicationController < ApplicationController ...@@ -81,10 +81,6 @@ class Projects::ApplicationController < ApplicationController
end end
end end
def apply_diff_view_cookie!
set_secure_cookie(:diff_view, params.delete(:view), type: COOKIE_TYPE_PERMANENT) if params[:view].present?
end
def require_pages_enabled! def require_pages_enabled!
not_found unless @project.pages_available? not_found unless @project.pages_available?
end end
......
...@@ -9,6 +9,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -9,6 +9,7 @@ class Projects::BlobController < Projects::ApplicationController
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
include RedirectsForMissingPathOnTree include RedirectsForMissingPathOnTree
include SourcegraphDecorator include SourcegraphDecorator
include DiffHelper
prepend_before_action :authenticate_user!, only: [:edit] prepend_before_action :authenticate_user!, only: [:edit]
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
class Projects::WikisController < Projects::ApplicationController class Projects::WikisController < Projects::ApplicationController
include WikiActions include WikiActions
include PreviewMarkdown
alias_method :container, :project alias_method :container, :project
......
...@@ -174,6 +174,10 @@ module DiffHelper ...@@ -174,6 +174,10 @@ module DiffHelper
end end
end end
def apply_diff_view_cookie!
set_secure_cookie(:diff_view, params.delete(:view), type: CookiesHelper::COOKIE_TYPE_PERMANENT) if params[:view].present?
end
private private
def diff_btn(title, name, selected) def diff_btn(title, name, selected)
......
...@@ -3,7 +3,7 @@ scope(controller: :wikis) do ...@@ -3,7 +3,7 @@ scope(controller: :wikis) do
get :git_access get :git_access
get :pages get :pages
get :new get :new
get '/', to: redirect('%{namespace_id}/%{project_id}/wikis/home') get '/', to: redirect { |params, request| "#{request.path}/home" }
post '/', to: 'wikis#create' post '/', to: 'wikis#create'
end end
......
import initWikis from '~/pages/shared/wikis';
document.addEventListener('DOMContentLoaded', initWikis);
# frozen_string_literal: true
class Groups::WikisController < Groups::ApplicationController
include WikiActions
alias_method :container, :group
private
def authorize_read_wiki!
access_denied! unless can?(current_user, :read_wiki, group)
end
def authorize_create_wiki!
access_denied! unless can?(current_user, :create_wiki, group)
end
def authorize_admin_wiki!
access_denied! unless can?(current_user, :admin_wiki, group)
end
end
...@@ -13,6 +13,8 @@ constraints(::Constraints::GroupUrlConstrainer.new) do ...@@ -13,6 +13,8 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
module: :groups, module: :groups,
as: :group, as: :group,
constraints: { group_id: Gitlab::PathRegex.full_namespace_route_regex }) do constraints: { group_id: Gitlab::PathRegex.full_namespace_route_regex }) do
draw :wiki
resources :group_members, only: [], concerns: :access_requestable do resources :group_members, only: [], concerns: :access_requestable do
patch :override, on: :member patch :override, on: :member
end end
......
...@@ -35,15 +35,14 @@ module EE ...@@ -35,15 +35,14 @@ module EE
end end
end end
override :wiki_page_url override :wiki_url
def wiki_page_url(wiki, page, **options) def wiki_url(wiki, **options)
if wiki.container.is_a?(Group) if wiki.container.is_a?(Group)
# TODO: Use the new route for group wikis once we add it. options[:controller] = 'groups/wikis'
# https://gitlab.com/gitlab-org/gitlab/-/issues/211360 options[:group_id] = wiki.container
instance.group_canonical_url(wiki.container, **options) + "/-/wikis/#{page.to_param}"
else
super
end end
super
end end
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Groups::WikisController do
it_behaves_like 'wiki controller actions' do
let(:container) { create(:group, :public) }
let(:routing_params) { { group_id: container } }
before do
container.add_owner(user)
stub_feature_flags(group_wiki: container)
end
context 'when the feature flag is disabled' do
before do
stub_feature_flags(group_wiki: false)
end
using RSpec::Parameterized::TableSyntax
where(:method, :action) do
:get | :new
:get | :pages
:post | :create
:get | :show
:get | :edit
:get | :history
:post | :preview_markdown
:put | :update
:delete | :destroy
end
with_them do
it 'returns a 404 error' do
process action, method: method, params: routing_params.merge(id: 'page')
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
end
...@@ -5,6 +5,10 @@ require 'spec_helper' ...@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe 'Group routing', "routing" do RSpec.describe 'Group routing', "routing" do
include RSpec::Rails::RoutingExampleGroup include RSpec::Rails::RoutingExampleGroup
before do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
end
describe 'subgroup "boards"' do describe 'subgroup "boards"' do
it 'shows group show page' do it 'shows group show page' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq/boards', any_args).and_return(true) allow(Group).to receive(:find_by_full_path).with('gitlabhq/boards', any_args).and_return(true)
...@@ -13,43 +17,29 @@ RSpec.describe 'Group routing', "routing" do ...@@ -13,43 +17,29 @@ RSpec.describe 'Group routing', "routing" do
end end
it 'shows boards index page' do it 'shows boards index page' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/boards')).to route_to('groups/boards#index', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/boards')).to route_to('groups/boards#index', group_id: 'gitlabhq')
end end
end end
describe 'security' do describe 'security' do
it 'shows group dashboard' do it 'shows group dashboard' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/security/dashboard')).to route_to('groups/security/dashboard#show', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/security/dashboard')).to route_to('groups/security/dashboard#show', group_id: 'gitlabhq')
end end
it 'lists vulnerabilities' do it 'lists vulnerabilities' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/security/vulnerability_findings')).to route_to('groups/security/vulnerability_findings#index', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/security/vulnerability_findings')).to route_to('groups/security/vulnerability_findings#index', group_id: 'gitlabhq')
end end
it 'shows vulnerability summary' do it 'shows vulnerability summary' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/security/vulnerability_findings/summary')).to route_to('groups/security/vulnerability_findings#summary', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/security/vulnerability_findings/summary')).to route_to('groups/security/vulnerability_findings#summary', group_id: 'gitlabhq')
end end
it 'shows vulnerability history' do it 'shows vulnerability history' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/security/vulnerability_findings/history')).to route_to('groups/security/vulnerability_findings#history', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/security/vulnerability_findings/history')).to route_to('groups/security/vulnerability_findings#history', group_id: 'gitlabhq')
end end
end end
describe 'dependency proxy for containers' do describe 'dependency proxy for containers' do
before do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
end
context 'image name without namespace' do context 'image name without namespace' do
it 'routes to #manifest' do it 'routes to #manifest' do
expect(get('/v2/gitlabhq/dependency_proxy/containers/ruby/manifests/2.3.6')) expect(get('/v2/gitlabhq/dependency_proxy/containers/ruby/manifests/2.3.6'))
...@@ -87,41 +77,48 @@ RSpec.describe 'Group routing', "routing" do ...@@ -87,41 +77,48 @@ RSpec.describe 'Group routing', "routing" do
describe 'hooks' do describe 'hooks' do
it 'routes to hooks edit page' do it 'routes to hooks edit page' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/hooks/2/edit')).to route_to('groups/hooks#edit', group_id: 'gitlabhq', id: '2') expect(get('/groups/gitlabhq/-/hooks/2/edit')).to route_to('groups/hooks#edit', group_id: 'gitlabhq', id: '2')
end end
end end
describe 'packages' do describe 'packages' do
it 'routes to packages index page' do it 'routes to packages index page' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(get('/groups/gitlabhq/-/packages')).to route_to('groups/packages#index', group_id: 'gitlabhq') expect(get('/groups/gitlabhq/-/packages')).to route_to('groups/packages#index', group_id: 'gitlabhq')
end end
end end
describe 'issues' do describe 'issues' do
it 'routes post to #bulk_update' do it 'routes post to #bulk_update' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(post('/groups/gitlabhq/-/issues/bulk_update')).to route_to('groups/issues#bulk_update', group_id: 'gitlabhq') expect(post('/groups/gitlabhq/-/issues/bulk_update')).to route_to('groups/issues#bulk_update', group_id: 'gitlabhq')
end end
end end
describe 'merge_requests' do describe 'merge_requests' do
it 'routes post to #bulk_update' do it 'routes post to #bulk_update' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(post('/groups/gitlabhq/-/merge_requests/bulk_update')).to route_to('groups/merge_requests#bulk_update', group_id: 'gitlabhq') expect(post('/groups/gitlabhq/-/merge_requests/bulk_update')).to route_to('groups/merge_requests#bulk_update', group_id: 'gitlabhq')
end end
end end
describe 'epics' do describe 'epics' do
it 'routes post to #bulk_update' do it 'routes post to #bulk_update' do
allow(Group).to receive(:find_by_full_path).with('gitlabhq', any_args).and_return(true)
expect(post('/groups/gitlabhq/-/epics/bulk_update')).to route_to('groups/epics#bulk_update', group_id: 'gitlabhq') expect(post('/groups/gitlabhq/-/epics/bulk_update')).to route_to('groups/epics#bulk_update', group_id: 'gitlabhq')
end end
end end
# group_wikis_git_access GET /:group_id/-/wikis/git_access(.:format) groups/wikis#git_access
# group_wikis_pages GET /:group_id/-/wikis/pages(.:format) groups/wikis#pages
# group_wikis_new GET /:group_id/-/wikis/new(.:format) groups/wikis#new
# POST /:group_id/-/wikis(.:format) groups/wikis#create
# group_wiki_edit GET /:group_id/-/wikis/*id/edit groups/wikis#edit
# group_wiki_history GET /:group_id/-/wikis/*id/history groups/wikis#history
# group_wiki_preview_markdown POST /:group_id/-/wikis/*id/preview_markdown groups/wikis#preview_markdown
# group_wiki GET /:group_id/-/wikis/*id groups/wikis#show
# PUT /:group_id/-/wikis/*id groups/wikis#update
# DELETE /:group_id/-/wikis/*id groups/wikis#destroy
describe Groups::WikisController, 'routing' do
it_behaves_like 'wiki routing' do
let(:base_path) { '/groups/gitlabhq/-/wikis' }
let(:base_params) { { group_id: 'gitlabhq' } }
end
end
end end
...@@ -85,9 +85,11 @@ module Gitlab ...@@ -85,9 +85,11 @@ module Gitlab
def wiki_url(wiki, **options) def wiki_url(wiki, **options)
return wiki_page_url(wiki, Wiki::HOMEPAGE, **options) unless options[:action] return wiki_page_url(wiki, Wiki::HOMEPAGE, **options) unless options[:action]
options[:controller] = 'projects/wikis' if wiki.container.is_a?(Project)
options[:namespace_id] = wiki.container.namespace options[:controller] = 'projects/wikis'
options[:project_id] = wiki.container options[:namespace_id] = wiki.container.namespace
options[:project_id] = wiki.container
end
instance.url_for(**options) instance.url_for(**options)
end end
......
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::WikisController do RSpec.describe Projects::WikisController do
it_behaves_like 'wiki controller actions' do it_behaves_like 'wiki controller actions' do
let(:container) { create(:project, :public, :repository, namespace: user.namespace) } let(:container) { create(:project, :public, namespace: user.namespace) }
let(:routing_params) { { namespace_id: container.namespace, project_id: container } } let(:routing_params) { { namespace_id: container.namespace, project_id: container } }
end end
end end
This diff is collapsed.
...@@ -147,6 +147,7 @@ RSpec.shared_examples 'wiki controller actions' do ...@@ -147,6 +147,7 @@ RSpec.shared_examples 'wiki controller actions' do
subject subject
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/show')
expect(assigns(:page).title).to eq(wiki_title) expect(assigns(:page).title).to eq(wiki_title)
expect(assigns(:sidebar_wiki_entries)).to contain_exactly(an_instance_of(WikiPage)) expect(assigns(:sidebar_wiki_entries)).to contain_exactly(an_instance_of(WikiPage))
expect(assigns(:sidebar_limited)).to be(false) expect(assigns(:sidebar_limited)).to be(false)
...@@ -159,6 +160,7 @@ RSpec.shared_examples 'wiki controller actions' do ...@@ -159,6 +160,7 @@ RSpec.shared_examples 'wiki controller actions' do
subject subject
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/show')
expect(flash[:notice]).to eq(_('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.')) expect(flash[:notice]).to eq(_('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.'))
end end
end end
...@@ -167,19 +169,37 @@ RSpec.shared_examples 'wiki controller actions' do ...@@ -167,19 +169,37 @@ RSpec.shared_examples 'wiki controller actions' do
context 'when the page does not exist' do context 'when the page does not exist' do
let(:id) { 'does not exist' } let(:id) { 'does not exist' }
before do context 'when the user can create pages' do
subject before do
end subject
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('shared/wikis/edit')
end
it 'builds a new wiki page with the id as the title' do
expect(assigns(:page).title).to eq(id)
end
context 'when a random_title param is present' do
let(:random_title) { true }
it 'builds a new wiki page with the id as the title' do it 'builds a new wiki page with no title' do
expect(assigns(:page).title).to eq(id) expect(assigns(:page).title).to be_empty
end
end
end end
context 'when a random_title param is present' do context 'when the user cannot create pages' do
let(:random_title) { true } before do
sign_out(:user)
end
it 'shows the empty state' do
subject
it 'builds a new wiki page with no title' do expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:page).title).to be_empty expect(response).to render_template('shared/wikis/empty')
end end
end end
end end
...@@ -195,6 +215,7 @@ RSpec.shared_examples 'wiki controller actions' do ...@@ -195,6 +215,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'delivers the file with the correct headers' do it 'delivers the file with the correct headers' do
subject subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Disposition']).to match(/^inline/) expect(response.headers['Content-Disposition']).to match(/^inline/)
expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq('true') expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq('true')
expect(response.cache_control[:public]).to be(false) expect(response.cache_control[:public]).to be(false)
...@@ -208,6 +229,7 @@ RSpec.shared_examples 'wiki controller actions' do ...@@ -208,6 +229,7 @@ RSpec.shared_examples 'wiki controller actions' do
it 'renders json in a correct format' do it 'renders json in a correct format' do
post :preview_markdown, params: routing_params.merge(id: 'page/path', text: '*Markdown* text') post :preview_markdown, params: routing_params.merge(id: 'page/path', text: '*Markdown* text')
expect(response).to have_gitlab_http_status(:ok)
expect(json_response.keys).to match_array(%w(body references)) expect(json_response.keys).to match_array(%w(body references))
end end
end end
......
# frozen_string_literal: true
# Shared examples for resource routes.
#
# By default it tests all the default REST actions: index, create, new, edit,
# show, update, and destroy. You can remove actions by customizing the
# `actions` variable.
#
# The subject is expected to be an instance of the controller under test.
#
# It also expects a `base_path` variable to be available which defines the
# base path of the controller, and a `base_params` variable which
# defines the route params the base path maps to.
#
# Examples
#
# # Default behavior
# describe Projects::CommitsController, 'routing' do
# it_behaves_like 'resource routing' do
# let(:base_path) { '/gitlab/gitlabhq/-/commits' }
# let(:base_params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } }
# end
# end
#
# # Customizing actions
# it_behaves_like 'resource routing' do
# let(:base_path) { '/gitlab/gitlabhq/-/commits' }
#
# # Specify default actions
# let(:actions) { [:index] }
#
# # Add custom actions by passing a hash with action names
# # as keys, and the HTTP method and path as values.
# let(:additional_actions) do
# {
# preview_markdown: [:post, '/:id/preview_markdown'],
# }
# end
# end
RSpec.shared_examples 'resource routing' do
let(:controller) { described_class.controller_path }
let(:id) { '123' }
let(:default_actions) do
{
index: [:get, ''],
show: [:get, '/:id'],
new: [:get, '/new'],
create: [:post, ''],
edit: [:get, '/:id/edit'],
update: [:put, '/:id'],
destroy: [:delete, '/:id']
}
end
let(:actions) { default_actions.keys }
let(:additional_actions) { {} }
it 'routes resource actions', :aggregate_failures do
selected_actions = default_actions.slice(*actions).merge(additional_actions)
selected_actions.each do |action, (method, action_path)|
expected_params = base_params.merge(controller: controller.to_s, action: action.to_s)
if action_path.include?(':id')
action_path = action_path.sub(':id', id)
expected_params[:id] = id
end
expect(public_send(method, "#{base_path}#{action_path}")).to route_to(expected_params)
end
end
end
# frozen_string_literal: true
RSpec.shared_examples 'wiki routing' do
it_behaves_like 'resource routing' do
let(:id) { 'directory/page' }
let(:actions) { %i[show new create edit update destroy] }
let(:additional_actions) do
{
pages: [:get, '/pages'],
history: [:get, '/:id/history'],
git_access: [:get, '/git_access'],
preview_markdown: [:post, '/:id/preview_markdown']
}
end
end
it 'redirects the base path to the home page', type: :request do
expect(get(base_path)).to redirect_to("#{base_path}/home")
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