Commit 0f52d259 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'init-from-ui' into 'master'

File creation and editing refactored

* Refactored controllers/helpers/views related to blob resource
* make it possible to create new file in empty repository

Second step in building #1930

See merge request !1440
parents 79915528 ed8c3e2d
class Projects::BaseTreeController < Projects::ApplicationController
include ExtractsPath
before_filter :authorize_download_code!
before_filter :require_non_empty_project
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class Projects::BlameController < Projects::ApplicationController class Projects::BlameController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
...@@ -2,16 +2,70 @@ ...@@ -2,16 +2,70 @@
class Projects::BlobController < Projects::ApplicationController class Projects::BlobController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize # Raised when given an invalid file path
class InvalidPathError < StandardError; end
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project, except: [:new, :create]
before_filter :authorize_push_code!, only: [:destroy] before_filter :authorize_push_code!, only: [:destroy]
before_filter :assign_blob_vars
before_filter :commit, except: [:new, :create]
before_filter :blob, except: [:new, :create]
before_filter :from_merge_request, only: [:edit, :update]
before_filter :after_edit_path, only: [:edit, :update]
before_filter :require_branch_head, only: [:edit, :update]
def new
commit unless @repository.empty?
end
before_filter :blob def create
file_path = File.join(@path, File.basename(params[:file_name]))
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_blob_path(@project, File.join(@ref, file_path))
else
flash[:alert] = result[:message]
render :new
end
end
def show def show
end end
def edit
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end
def update
result = Files::UpdateService.
new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
if from_merge_request
from_merge_request.reload_code
end
redirect_to after_edit_path
else
flash[:alert] = result[:message]
render :edit
end
end
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
end
def destroy def destroy
result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
...@@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController
if @blob if @blob
@blob @blob
elsif tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
else else
if tree = @repository.tree(@commit.id, @path)
if tree.entries.any?
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
end
end
return not_found! return not_found!
end end
end end
def commit
@commit = @repository.commit(@ref)
return not_found! unless @commit
end
def assign_blob_vars
@id = params[:id]
@ref, @path = extract_ref(@id)
rescue InvalidPathError
not_found!
end
def after_edit_path
@after_edit_path ||=
if from_merge_request
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
"#file-path-#{hexdigest(@path)}"
else
project_blob_path(@project, @id)
end
end
def from_merge_request
# If blob edit was initiated from merge request page
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
end
end end
...@@ -3,7 +3,7 @@ require "base64" ...@@ -3,7 +3,7 @@ require "base64"
class Projects::CommitsController < Projects::ApplicationController class Projects::CommitsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::EditTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :blob
before_filter :authorize_push_code!
before_filter :from_merge_request
before_filter :after_edit_path
def show
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end
def update
result = Files::UpdateService.
new(@project, current_user, params, @ref, @path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
if from_merge_request
from_merge_request.reload_code
end
redirect_to after_edit_path
else
flash[:alert] = result[:message]
render :show
end
end
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
render layout: false
end
private
def blob
@blob ||= @repository.blob_at(@commit.id, @path)
end
def after_edit_path
@after_edit_path ||=
if from_merge_request
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
"#file-path-#{hexdigest(@path)}"
else
project_blob_path(@project, @id)
end
end
def from_merge_request
# If blob edit was initiated from merge request page
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
end
end
...@@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController ...@@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
include ApplicationHelper include ApplicationHelper
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::NewTreeController < Projects::BaseTreeController
before_filter :require_branch_head
before_filter :authorize_push_code!
def show
end
def update
file_path = File.join(@path, File.basename(params[:file_name]))
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
if result[:status] == :success
flash[:notice] = "Your changes have been successfully committed"
redirect_to project_blob_path(@project, File.join(@ref, file_path))
else
flash[:alert] = result[:message]
render :show
end
end
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class Projects::RawController < Projects::ApplicationController class Projects::RawController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
class Projects::RefsController < Projects::ApplicationController class Projects::RefsController < Projects::ApplicationController
include ExtractsPath include ExtractsPath
# Authorize before_filter :assign_ref_vars
before_filter :authorize_download_code! before_filter :authorize_download_code!
before_filter :require_non_empty_project before_filter :require_non_empty_project
......
# Controller for viewing a repository's file structure # Controller for viewing a repository's file structure
class Projects::TreeController < Projects::BaseTreeController class Projects::TreeController < Projects::ApplicationController
def show include ExtractsPath
before_filter :assign_ref_vars
before_filter :authorize_download_code!
before_filter :require_non_empty_project, except: [:new, :create]
def show
if tree.entries.empty? if tree.entries.empty?
if @repository.blob_at(@commit.id, @path) if @repository.blob_at(@commit.id, @path)
redirect_to project_blob_path(@project, File.join(@ref, @path)) and return redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
......
...@@ -19,4 +19,42 @@ module BlobHelper ...@@ -19,4 +19,42 @@ module BlobHelper
def no_highlight_files def no_highlight_files
%w(credits changelog copying copyright license authors) %w(credits changelog copying copyright license authors)
end end
def edit_blob_link(project, ref, path, options = {})
blob =
begin
project.repository.blob_at(ref, path)
rescue
nil
end
if blob && blob.text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_blob_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end
end
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
def editing_preview_title(filename)
if Gitlab::MarkdownHelper.previewable?(filename)
'Preview'
else
'Preview changes'
end
end
end end
...@@ -187,7 +187,11 @@ module ProjectsHelper ...@@ -187,7 +187,11 @@ module ProjectsHelper
"Issues - " + title "Issues - " + title
end end
elsif current_controller?(:blob) elsif current_controller?(:blob)
"#{@project.path}\/#{@blob.path} at #{@ref} - " + title if current_action?(:new) || current_action?(:create)
"New file at #{@ref}"
elsif @blob
"Edit file #{@blob.path} at #{@ref}"
end
elsif current_controller?(:commits) elsif current_controller?(:commits)
"Commits at #{@ref} - " + title "Commits at #{@ref} - " + title
elsif current_controller?(:merge_requests) elsif current_controller?(:merge_requests)
......
...@@ -64,32 +64,6 @@ module TreeHelper ...@@ -64,32 +64,6 @@ module TreeHelper
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref) ::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
end end
def edit_blob_link(project, ref, path, options = {})
blob =
begin
project.repository.blob_at(ref, path)
rescue
nil
end
if blob && blob.text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_tree_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end
end
def tree_breadcrumbs(tree, max_links = 2) def tree_breadcrumbs(tree, max_links = 2)
if @path.present? if @path.present?
part_path = "" part_path = ""
...@@ -121,16 +95,4 @@ module TreeHelper ...@@ -121,16 +95,4 @@ module TreeHelper
return tree.name return tree.name
end end
end end
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
def editing_preview_title(filename)
if Gitlab::MarkdownHelper.previewable?(filename)
'Preview'
else
'Diff'
end
end
end end
.file-editor .file-editor
%ul.nav.nav-tabs.js-edit-mode %ul.nav.nav-tabs.js-edit-mode
%li.active %li.active
= link_to 'Edit', '#editor' = link_to '#editor' do
%i.fa.fa-edit
Edit file
%li %li
= link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id) = link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
%i.fa.fa-eye
= editing_preview_title(@blob.name)
= form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do = form_tag(project_update_blob_path(@project, @id), method: :put, class: "form-horizontal") do
= render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data = render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
= render 'shared/commit_message_container', params: params, = render 'shared/commit_message_container', params: params,
placeholder: "Update #{@blob.name}" placeholder: "Update #{@blob.name}"
......
%h3.page-title New file %h3.page-title New file
%hr %hr
.file-editor .file-editor
= form_tag(project_new_tree_path(@project, @id), method: :put, class: 'form-horizontal form-new-file') do = form_tag(project_create_blob_path(@project, @id), method: :post, class: 'form-horizontal form-new-file') do
.form-group.commit_message-group .form-group.commit_message-group
= label_tag 'file_name', class: 'control-label' do = label_tag 'file_name', class: 'control-label' do
File name File name
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
The repository for this project is empty The repository for this project is empty
%p.lead %p.lead
You can You can
= link_to '#', class: 'btn btn-new btn-lg' do = link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
add a file add a file
&nbsp;or push it via command line. &nbsp;or push it via command line.
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= link_to title, '#' = link_to title, '#'
- if current_user && can_push_branch?(@project, @ref) - if current_user && can_push_branch?(@project, @ref)
%li %li
= link_to project_new_tree_path(@project, @id), title: 'New file', id: 'new-file-link' do = link_to project_new_blob_path(@project, @id), title: 'New file', id: 'new-file-link' do
%small %small
%i.fa.fa-plus %i.fa.fa-plus
......
...@@ -211,17 +211,20 @@ Gitlab::Application.routes.draw do ...@@ -211,17 +211,20 @@ Gitlab::Application.routes.draw do
end end
scope module: :projects do scope module: :projects do
# Blob routes:
get '/new/:id', to: 'blob#new', constraints: {id: /.+/}, as: 'new_blob'
post '/create/:id', to: 'blob#create', constraints: {id: /.+/}, as: 'create_blob'
get '/edit/:id', to: 'blob#edit', constraints: {id: /.+/}, as: 'edit_blob'
put '/update/:id', to: 'blob#update', constraints: {id: /.+/}, as: 'update_blob'
post '/preview/:id', to: 'blob#preview', constraints: {id: /.+/}, as: 'preview_blob'
resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
get :diff, on: :member get :diff, on: :member
end end
resources :raw, only: [:show], constraints: {id: /.+/} resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do
# Cannot be GET to differentiate from GET paths that end in preview.
post :preview, on: :member
end
resource :avatar, only: [:show, :destroy] resource :avatar, only: [:show, :destroy]
resources :new_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'new'
resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/} resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
resources :compare, only: [:index, :create] resources :compare, only: [:index, :create]
......
...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -78,7 +78,7 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end end
step 'I click link "Diff"' do step 'I click link "Diff"' do
click_link 'Diff' click_link 'Preview changes'
end end
step 'I click on "Commit Changes"' do step 'I click on "Commit Changes"' do
......
...@@ -284,11 +284,11 @@ module SharedPaths ...@@ -284,11 +284,11 @@ module SharedPaths
end end
step 'I am on the new file page' do step 'I am on the new file page' do
current_path.should eq(project_new_tree_path(@project, root_ref)) current_path.should eq(project_create_blob_path(@project, root_ref))
end end
step 'I am on the ".gitignore" edit file page' do step 'I am on the ".gitignore" edit file page' do
current_path.should eq(project_edit_tree_path( current_path.should eq(project_edit_blob_path(
@project, File.join(root_ref, '.gitignore'))) @project, File.join(root_ref, '.gitignore')))
end end
......
# Module providing methods for dealing with separating a tree-ish string and a # Module providing methods for dealing with separating a tree-ish string and a
# file path string when combined in a request parameter # file path string when combined in a request parameter
module ExtractsPath module ExtractsPath
extend ActiveSupport::Concern
# Raised when given an invalid file path # Raised when given an invalid file path
class InvalidPathError < StandardError; end class InvalidPathError < StandardError; end
included do
if respond_to?(:before_filter)
before_filter :assign_ref_vars
end
end
# Given a string containing both a Git tree-ish, such as a branch or tag, and # Given a string containing both a Git tree-ish, such as a branch or tag, and
# a filesystem path joined by forward slashes, attempts to separate the two. # a filesystem path joined by forward slashes, attempts to separate the two.
# #
......
...@@ -430,21 +430,17 @@ describe Projects::TreeController, 'routing' do ...@@ -430,21 +430,17 @@ describe Projects::TreeController, 'routing' do
end end
end end
describe Projects::EditTreeController, 'routing' do describe Projects::BlobController, 'routing' do
it 'to #show' do it 'to #edit' do
get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should( get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should(
route_to('projects/edit_tree#show', route_to('projects/blob#edit',
project_id: 'gitlab/gitlabhq', project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb')) id: 'master/app/models/project.rb'))
get('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
route_to('projects/edit_tree#show',
project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb/preview'))
end end
it 'to #preview' do it 'to #preview' do
post('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should( post('/gitlab/gitlabhq/preview/master/app/models/project.rb').should(
route_to('projects/edit_tree#preview', route_to('projects/blob#preview',
project_id: 'gitlab/gitlabhq', project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb')) id: 'master/app/models/project.rb'))
end end
......
...@@ -48,7 +48,7 @@ describe MergeRequests::UpdateService do ...@@ -48,7 +48,7 @@ describe MergeRequests::UpdateService do
end end
it 'should create system note about merge_request reassign' do it 'should create system note about merge_request reassign' do
note = @merge_request.notes.reload.last note = @merge_request.notes.last
note.note.should include "Reassigned to \@#{user2.username}" note.note.should include "Reassigned to \@#{user2.username}"
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment