Merge remote-tracking branch 'official/master' into saltation
[gitorious:taladars-gitorious-saltation.git] / app / controllers / comments_controller.rb
1 # encoding: utf-8
2 #--
3 #   Copyright (C) 2010 Marko Peltola <marko@markopeltola.com>
4 #   Copyright (C) 2010 Tero Hänninen <tero.j.hanninen@jyu.fi>
5 #   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
6 #   Copyright (C) 2008 Johan Sørensen <johan@johansorensen.com>
7 #   Copyright (C) 2008 David A. Cuadrado <krawek@gmail.com>
8 #   Copyright (C) 2008 Tor Arne Vestbø <tavestbo@trolltech.com>
9 #   Copyright (C) 2009 Fabio Akita <fabio.akita@gmail.com>
10 #
11 #   This program is free software: you can redistribute it and/or modify
12 #   it under the terms of the GNU Affero General Public License as published by
13 #   the Free Software Foundation, either version 3 of the License, or
14 #   (at your option) any later version.
15 #
16 #   This program is distributed in the hope that it will be useful,
17 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
18 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 #   GNU Affero General Public License for more details.
20 #
21 #   You should have received a copy of the GNU Affero General Public License
22 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 #++
24
25 class CommentsController < ApplicationController
26   before_filter :login_required, :only => [:new, :create, :edit, :update, :destroy]
27   before_filter :find_project_and_repository
28   before_filter :require_view_right_to_repository
29   before_filter :find_polymorphic_parent
30   before_filter :comment_should_be_editable, :only => [:edit, :update]
31   renders_in_site_specific_context
32
33   def index
34     @comments = @target.comments.find(:all, :include => :user)
35     @merge_request_count = @repository.merge_requests.count_open
36     @atom_auto_discovery_url = project_repository_comments_path(@project, @repository,
37       :format => :atom)
38     respond_to do |format|
39       format.html { }
40       format.atom { }
41     end
42   end
43   
44   def preview
45     @comment = Comment.new(params[:comment])
46     respond_to do |wants|
47       wants.js
48     end
49   end
50   
51   def new
52     @comment = @target.comments.new
53   end
54   
55   def create
56     state = params[:comment].delete(:state)
57     @comment = @target.comments.new(params[:comment])
58     @comment.user = current_user
59     @comment.state = state
60     @comment.project = @project
61     render_or_redirect
62   end
63
64   def edit
65     render :partial => "edit_body"
66   end
67
68   def update
69     @comment.body = params[:comment][:body]
70     @comment.save
71     render :partial => @comment
72   end
73   
74   protected
75   def render_or_redirect
76     if @comment.save
77       comment_was_created
78     else
79       comment_was_invalid
80     end
81   end
82
83   def comment_was_created
84     create_new_commented_posted_event
85     add_to_favorites if params[:add_to_favorites]
86     respond_to do |wants|
87       wants.html do
88         flash[:success] = I18n.t "comments_controller.create_success"
89         if @comment.sha1.blank?
90           redirect_to_repository_or_target
91         else
92           redirect_to repo_owner_path(@repository,
93             :project_repository_commit_path, @project, @repository, @comment.sha1)
94         end
95       end
96       wants.js do
97         case @target
98         when Repository
99           commit = @target.git.commit(@comment.sha1)
100           @comments = @target.comments.find_all_by_sha1(@comment.sha1, :include => :user)
101           @diffs = commit.parents.empty? ? [] : commit.diffs.select { |diff|
102             diff.a_path == @comment.path
103           }
104           @file_diff = render_to_string(:partial => "commits/diffs")
105         else
106           @diffs = @target.diffs(range_or_string(@comment.sha1)).select{|d|
107             d.a_path == @comment.path
108           }
109           @file_diff = render_to_string(:partial => "merge_request_versions/comments")
110         end
111         render :json => {
112           "file-diff" => @file_diff,
113           "comment" => render_to_string(:partial => @comment)
114         }, :status => :created
115       end
116     end
117   end
118
119   def add_to_favorites
120     favorite_target.watched_by!(current_user)
121   end
122
123   def favorite_target
124     @target.is_a?(MergeRequest) ? @target : @target.merge_request
125   end
126   
127   def comment_was_invalid
128     respond_to { |wants|
129       wants.html { render :action => "new" }
130       wants.js   { render :nothing => true, :status => :not_acceptable }
131     }
132   end
133   
134   def applies_to_merge_request_version?
135     MergeRequestVersion === @target
136   end
137
138   def range_or_string(str)
139     if match = /^([a-z0-9]*)-([a-z0-9]*)$/.match(str)
140       @sha_range = Range.new(match[1],match[2])
141     else
142       @sha_range = str
143     end
144   end
145
146   def find_repository
147     @repository = @owner.repositories.find_by_name_in_project!(params[:repository_id],
148       @containing_project)
149   end
150
151   def find_polymorphic_parent
152     if params[:merge_request_version_id]
153       @target = MergeRequestVersion.find(params[:merge_request_version_id])
154     elsif params[:merge_request_id]
155       @target = @repository.merge_requests.find_by_sequence_number!(params[:merge_request_id])
156     else
157       @target = @repository
158     end
159   end
160
161   def redirect_to_repository_or_target
162     if @target == @repository
163       redirect_to repo_owner_path(@repository, [@project, @target, :comments])
164     else
165       redirect_to repo_owner_path(@repository, [@project, @repository, @target])
166     end
167   end
168
169   def create_new_commented_posted_event
170     if applies_to_merge_request_version?
171       @project.create_event(Action::COMMENT, @target.merge_request, current_user,
172         @comment.to_param, "MergeRequest")
173       return
174     end
175
176     if @target == @repository
177       @project.create_event(Action::COMMENT, @repository, current_user,
178         @comment.to_param, "Repository")
179     else
180       @project.create_event(Action::COMMENT, @target, current_user,
181         @comment.to_param, "MergeRequest") if @comment.state_change.blank?
182     end
183   end
184
185   def comment_should_be_editable
186     @comment = Comment.find(params[:id])
187     if !@comment.editable_by?(current_user)
188       render :status => :unauthorized, :text => "Sorry mate"
189     end
190   end
191 end