@@ -0,0 +1,39 | |||
|
1 | # redMine - project management software | |
|
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or | |
|
5 | # modify it under the terms of the GNU General Public License | |
|
6 | # as published by the Free Software Foundation; either version 2 | |
|
7 | # of the License, or (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software | |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
|
17 | ||
|
18 | class AttachmentsController < ApplicationController | |
|
19 | before_filter :find_project, :check_project_privacy | |
|
20 | ||
|
21 | # sends an attachment | |
|
22 | def download | |
|
23 | send_file @attachment.diskfile, :filename => @attachment.filename | |
|
24 | end | |
|
25 | ||
|
26 | # sends an image to be displayed inline | |
|
27 | def show | |
|
28 | render(:nothing => true, :status => 404) and return unless @attachment.diskfile =~ /\.(jpeg|jpg|gif|png)$/i | |
|
29 | send_file @attachment.diskfile, :type => "image/#{$1}", :disposition => 'inline' | |
|
30 | end | |
|
31 | ||
|
32 | private | |
|
33 | def find_project | |
|
34 | @attachment = Attachment.find(params[:id]) | |
|
35 | @project = @attachment.project | |
|
36 | rescue | |
|
37 | render_404 | |
|
38 | end | |
|
39 | end |
@@ -0,0 +1,25 | |||
|
1 | # redMine - project management software | |
|
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
|
3 | # | |
|
4 | # This program is free software; you can redistribute it and/or | |
|
5 | # modify it under the terms of the GNU General Public License | |
|
6 | # as published by the Free Software Foundation; either version 2 | |
|
7 | # of the License, or (at your option) any later version. | |
|
8 | # | |
|
9 | # This program is distributed in the hope that it will be useful, | |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
|
12 | # GNU General Public License for more details. | |
|
13 | # | |
|
14 | # You should have received a copy of the GNU General Public License | |
|
15 | # along with this program; if not, write to the Free Software | |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
|
17 | ||
|
18 | module AttachmentsHelper | |
|
19 | # displays the links to a collection of attachments | |
|
20 | def link_to_attachments(attachments, options = {}) | |
|
21 | if attachments.any? | |
|
22 | render :partial => 'attachments/links', :locals => {:attachments => attachments, :options => options} | |
|
23 | end | |
|
24 | end | |
|
25 | end |
@@ -0,0 +1,4 | |||
|
1 | <p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%> | |
|
2 | <%= image_to_function "add.png", "addFileField();return false" %></label> | |
|
3 | ||
|
4 | <%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p> |
@@ -0,0 +1,13 | |||
|
1 | <div class="attachments"> | |
|
2 | <% for attachment in attachments %> | |
|
3 | <p><%= link_to attachment.filename, {:controller => 'attachments', :action => 'download', :id => attachment }, :class => 'icon icon-attachment' %> | |
|
4 | (<%= number_to_human_size attachment.filesize %>) | |
|
5 | <% unless options[:no_author] %> | |
|
6 | <em><%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %></em> | |
|
7 | <% end %> | |
|
8 | <% if options[:delete_url] %> | |
|
9 | <%= link_to image_tag('delete.png'), options[:delete_url].update({:attachment_id => attachment}), :confirm => l(:text_are_you_sure), :method => :post %> | |
|
10 | <% end %> | |
|
11 | </p> | |
|
12 | <% end %> | |
|
13 | </div> |
@@ -0,0 +1,11 | |||
|
1 | class AddWikiAttachmentsPermissions < ActiveRecord::Migration | |
|
2 | def self.up | |
|
3 | Permission.create :controller => 'wiki', :action => 'add_attachment', :description => 'label_attachment_new', :sort => 1750, :is_public => false, :mail_option => 0, :mail_enabled => 0 | |
|
4 | Permission.create :controller => 'wiki', :action => 'destroy_attachment', :description => 'label_attachment_delete', :sort => 1755, :is_public => false, :mail_option => 0, :mail_enabled => 0 | |
|
5 | end | |
|
6 | ||
|
7 | def self.down | |
|
8 | Permission.find_by_controller_and_action('wiki', 'add_attachment').destroy | |
|
9 | Permission.find_by_controller_and_action('wiki', 'destroy_attachment').destroy | |
|
10 | end | |
|
11 | end |
@@ -29,6 +29,8 class IssuesController < ApplicationController | |||
|
29 | 29 | include IssueRelationsHelper |
|
30 | 30 | helper :watchers |
|
31 | 31 | include WatchersHelper |
|
32 | helper :attachments | |
|
33 | include AttachmentsHelper | |
|
32 | 34 | |
|
33 | 35 | def show |
|
34 | 36 | @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user |
@@ -146,14 +148,6 class IssuesController < ApplicationController | |||
|
146 | 148 | redirect_to :action => 'show', :id => @issue |
|
147 | 149 | end |
|
148 | 150 | |
|
149 | # Send the file in stream mode | |
|
150 | def download | |
|
151 | @attachment = @issue.attachments.find(params[:attachment_id]) | |
|
152 | send_file @attachment.diskfile, :filename => @attachment.filename | |
|
153 | rescue | |
|
154 | render_404 | |
|
155 | end | |
|
156 | ||
|
157 | 151 | private |
|
158 | 152 | def find_project |
|
159 | 153 | @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) |
@@ -22,6 +22,9 class MessagesController < ApplicationController | |||
|
22 | 22 | |
|
23 | 23 | verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } |
|
24 | 24 | |
|
25 | helper :attachments | |
|
26 | include AttachmentsHelper | |
|
27 | ||
|
25 | 28 | def show |
|
26 | 29 | @reply = Message.new(:subject => "RE: #{@message.subject}") |
|
27 | 30 | render :action => "show", :layout => false if request.xhr? |
@@ -48,13 +51,6 class MessagesController < ApplicationController | |||
|
48 | 51 | redirect_to :action => 'show', :id => @message |
|
49 | 52 | end |
|
50 | 53 | |
|
51 | def download | |
|
52 | @attachment = @message.attachments.find(params[:attachment_id]) | |
|
53 | send_file @attachment.diskfile, :filename => @attachment.filename | |
|
54 | rescue | |
|
55 | render_404 | |
|
56 | end | |
|
57 | ||
|
58 | 54 | private |
|
59 | 55 | def find_project |
|
60 | 56 | @board = Board.find(params[:board_id], :include => :project) |
@@ -17,10 +17,13 | |||
|
17 | 17 | |
|
18 | 18 | class WikiController < ApplicationController |
|
19 | 19 | layout 'base' |
|
20 |
before_filter :find_wiki, :check_project_privacy |
|
|
21 | before_filter :authorize, :only => :destroy | |
|
20 | before_filter :find_wiki, :check_project_privacy | |
|
21 | before_filter :authorize, :only => [:destroy, :add_attachment, :destroy_attachment] | |
|
22 | 22 | |
|
23 |
verify :method => :post, :only => [ :destroy |
|
|
23 | verify :method => :post, :only => [:destroy, :destroy_attachment], :redirect_to => { :action => :index } | |
|
24 | ||
|
25 | helper :attachments | |
|
26 | include AttachmentsHelper | |
|
24 | 27 | |
|
25 | 28 | # display a page (in editing mode if it doesn't exist) |
|
26 | 29 | def index |
@@ -107,10 +110,28 class WikiController < ApplicationController | |||
|
107 | 110 | end |
|
108 | 111 | |
|
109 | 112 | def preview |
|
113 | page = @wiki.find_page(params[:page]) | |
|
114 | @attachements = page.attachments if page | |
|
110 | 115 | @text = params[:content][:text] |
|
111 | 116 | render :partial => 'preview' |
|
112 | 117 | end |
|
113 | 118 | |
|
119 | def add_attachment | |
|
120 | @page = @wiki.find_page(params[:page]) | |
|
121 | # Save the attachments | |
|
122 | params[:attachments].each { |file| | |
|
123 | next unless file.size > 0 | |
|
124 | a = Attachment.create(:container => @page, :file => file, :author => logged_in_user) | |
|
125 | } if params[:attachments] and params[:attachments].is_a? Array | |
|
126 | redirect_to :action => 'index', :page => @page.title | |
|
127 | end | |
|
128 | ||
|
129 | def destroy_attachment | |
|
130 | @page = @wiki.find_page(params[:page]) | |
|
131 | @page.attachments.find(params[:attachment_id]).destroy | |
|
132 | redirect_to :action => 'index', :page => @page.title | |
|
133 | end | |
|
134 | ||
|
114 | 135 | private |
|
115 | 136 | |
|
116 | 137 | def find_wiki |
@@ -146,7 +146,24 module ApplicationHelper | |||
|
146 | 146 | # example: |
|
147 | 147 | # r52 -> <a href="/repositories/revision/6?rev=52">r52</a> (@project.id is 6) |
|
148 | 148 | text = text.gsub(/(?=\b)r(\d+)(?=\b)/) {|m| link_to "r#{$1}", :controller => 'repositories', :action => 'revision', :id => @project.id, :rev => $1} if @project |
|
149 | ||
|
149 | ||
|
150 | # when using an image link, try to use an attachment, if possible | |
|
151 | attachments = options[:attachments] | |
|
152 | if attachments | |
|
153 | text = text.gsub(/!([<>=]*)(\S+\.(gif|jpg|jpeg|png))!/) do |m| | |
|
154 | align = $1 | |
|
155 | filename = $2 | |
|
156 | rf = Regexp.new(filename, Regexp::IGNORECASE) | |
|
157 | # search for the picture in attachments | |
|
158 | if found = attachments.detect { |att| att.filename =~ rf } | |
|
159 | image_url = url_for :controller => 'attachments', :action => 'show', :id => found.id | |
|
160 | "!#{align}#{image_url}!" | |
|
161 | else | |
|
162 | "!#{align}#{filename}!" | |
|
163 | end | |
|
164 | end | |
|
165 | end | |
|
166 | ||
|
150 | 167 | # finally textilize text |
|
151 | 168 | @do_textilize ||= (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") |
|
152 | 169 | text = @do_textilize ? auto_link(RedCloth.new(text, [:hard_breaks]).to_html) : simple_format(auto_link(h(text))) |
@@ -77,7 +77,11 class Attachment < ActiveRecord::Base | |||
|
77 | 77 | def self.most_downloaded |
|
78 | 78 | find(:all, :limit => 5, :order => "downloads DESC") |
|
79 | 79 | end |
|
80 | ||
|
80 | ||
|
81 | def project | |
|
82 | container.is_a?(Project) ? container : container.project | |
|
83 | end | |
|
84 | ||
|
81 | 85 | private |
|
82 | 86 | def sanitize_filename(value) |
|
83 | 87 | # get only the filename, not the whole path |
@@ -34,4 +34,8 class Message < ActiveRecord::Base | |||
|
34 | 34 | board.increment! :topics_count |
|
35 | 35 | end |
|
36 | 36 | end |
|
37 | ||
|
38 | def project | |
|
39 | board.project | |
|
40 | end | |
|
37 | 41 | end |
@@ -31,7 +31,8 class Wiki < ActiveRecord::Base | |||
|
31 | 31 | |
|
32 | 32 | # find the page with the given title |
|
33 | 33 | def find_page(title) |
|
34 | pages.find_by_title(Wiki.titleize(title || start_page)) | |
|
34 | title = start_page if title.blank? | |
|
35 | pages.find_by_title(Wiki.titleize(title)) | |
|
35 | 36 | end |
|
36 | 37 | |
|
37 | 38 | # turn a string into a valid page title |
@@ -18,6 +18,7 | |||
|
18 | 18 | class WikiPage < ActiveRecord::Base |
|
19 | 19 | belongs_to :wiki |
|
20 | 20 | has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy |
|
21 | has_many :attachments, :as => :container, :dependent => :destroy | |
|
21 | 22 | |
|
22 | 23 | validates_presence_of :title |
|
23 | 24 | validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/ |
@@ -41,4 +42,8 class WikiPage < ActiveRecord::Base | |||
|
41 | 42 | def self.pretty_title(str) |
|
42 | 43 | (str && str.is_a?(String)) ? str.tr('_', ' ') : str |
|
43 | 44 | end |
|
45 | ||
|
46 | def project | |
|
47 | wiki.project | |
|
48 | end | |
|
44 | 49 | end |
@@ -52,7 +52,7 end %> | |||
|
52 | 52 | <% end %> |
|
53 | 53 | |
|
54 | 54 | <b><%=l(:field_description)%> :</b><br /><br /> |
|
55 | <%= textilizable @issue.description %> | |
|
55 | <%= textilizable @issue.description, :attachments => @issue.attachments %> | |
|
56 | 56 | <br /> |
|
57 | 57 | |
|
58 | 58 | <div class="contextual"> |
@@ -92,24 +92,14 end %> | |||
|
92 | 92 | |
|
93 | 93 | <div class="box"> |
|
94 | 94 | <h3><%=l(:label_attachment_plural)%></h3> |
|
95 | <table width="100%"> | |
|
96 | <% for attachment in @issue.attachments %> | |
|
97 | <tr> | |
|
98 | <td><%= link_to attachment.filename, { :action => 'download', :id => @issue, :attachment_id => attachment }, :class => 'icon icon-attachment' %> (<%= number_to_human_size(attachment.filesize) %>)</td> | |
|
99 | <td><%= format_date(attachment.created_on) %></td> | |
|
100 | <td><%= attachment.author.display_name %></td> | |
|
101 | <td><div class="contextual"><%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy_attachment', :id => @issue, :attachment_id => attachment }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %></div></td> | |
|
102 | </tr> | |
|
103 | <% end %> | |
|
104 | </table> | |
|
105 | <br /> | |
|
95 | <%= link_to_attachments @issue.attachments, :delete_url => (authorize_for('issues', 'destroy_attachment') ? {:controller => 'issues', :action => 'destroy_attachment', :id => @issue} : nil) %> | |
|
96 | ||
|
106 | 97 | <% if authorize_for('issues', 'add_attachment') %> |
|
107 | <% form_tag({ :controller => 'issues', :action => 'add_attachment', :id => @issue }, :multipart => true, :class => "tabular") do %> | |
|
108 | <p id="attachments_p"><label><%=l(:label_attachment_new)%> | |
|
109 | <%= image_to_function "add.png", "addFileField();return false" %></label> | |
|
110 | <%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p> | |
|
111 | <%= submit_tag l(:button_add) %> | |
|
112 | <% end %> | |
|
98 | <p><%= toggle_link l(:label_attachment_new), "add_attachment_form" %></p> | |
|
99 | <% form_tag({ :controller => 'issues', :action => 'add_attachment', :id => @issue }, :multipart => true, :class => "tabular", :id => "add_attachment_form", :style => "display:none;") do %> | |
|
100 | <%= render :partial => 'attachments/form' %> | |
|
101 | <%= submit_tag l(:button_add) %> | |
|
102 | <% end %> | |
|
113 | 103 | <% end %> |
|
114 | 104 | </div> |
|
115 | 105 |
@@ -10,8 +10,5 | |||
|
10 | 10 | <!--[eoform:message]--> |
|
11 | 11 | |
|
12 | 12 | <span class="tabular"> |
|
13 | <p id="attachments_p"><label><%=l(:label_attachment)%> | |
|
14 | <%= image_to_function "add.png", "addFileField();return false" %></label> | |
|
15 | <%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p> | |
|
16 | </span> | |
|
13 | <%= render :partial => 'attachments/form' %> | |
|
17 | 14 | </div> |
@@ -2,15 +2,10 | |||
|
2 | 2 | |
|
3 | 3 | <p><em><%= @message.author.name %>, <%= format_time(@message.created_on) %></em></p> |
|
4 | 4 | <div class="wiki"> |
|
5 | <%= textilizable(@message.content) %> | |
|
5 | <%= textilizable(@message.content, :attachments => @message.attachments) %> | |
|
6 | 6 | </div> |
|
7 | <div class="attachments"> | |
|
8 | <% @message.attachments.each do |attachment| %> | |
|
9 | <%= link_to attachment.filename, { :action => 'download', :id => @message, :attachment_id => attachment }, :class => 'icon icon-attachment' %> | |
|
10 | (<%= number_to_human_size(attachment.filesize) %>)<br /> | |
|
11 | <% end %> | |
|
12 | </div> | |
|
13 | <br /> | |
|
7 | <%= link_to_attachments @message.attachments, :no_author => true %> | |
|
8 | ||
|
14 | 9 | <h3 class="icon22 icon22-comment"><%= l(:label_reply_plural) %></h3> |
|
15 | 10 | <% @message.children.each do |message| %> |
|
16 | 11 | <a name="<%= "message-#{message.id}" %>"></a> |
@@ -28,4 +23,4 | |||
|
28 | 23 | <p><%= submit_tag l(:button_submit) %></p> |
|
29 | 24 | <% end %> |
|
30 | 25 | </div> |
|
31 | <% end %> No newline at end of file | |
|
26 | <% end %> |
@@ -1,3 +1,3 | |||
|
1 | 1 | <fieldset class="preview"><legend><%= l(:label_preview) %></legend> |
|
2 | <%= textilizable @text %> | |
|
2 | <%= textilizable @text, :attachments => @attachements %> | |
|
3 | 3 | </fieldset> |
@@ -21,12 +21,22 | |||
|
21 | 21 | |
|
22 | 22 | <div class="wiki"> |
|
23 | 23 | <% cache "wiki/show/#{@page.id}/#{@content.version}" do %> |
|
24 | <%= textilizable @content.text %> | |
|
24 | <%= textilizable @content.text, :attachments => @page.attachments %> | |
|
25 | 25 | <% end %> |
|
26 | 26 | </div> |
|
27 | 27 | |
|
28 | <%= link_to_attachments @page.attachments, :delete_url => (authorize_for('wiki', 'destroy_attachment') ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %> | |
|
29 | ||
|
28 | 30 | <div class="contextual"> |
|
29 | 31 | <%= l(:label_export_to) %> |
|
30 | 32 | <%= link_to 'HTML', {:export => 'html', :version => @content.version}, :class => 'icon icon-html' %>, |
|
31 | 33 | <%= link_to 'TXT', {:export => 'txt', :version => @content.version}, :class => 'icon icon-txt' %> |
|
32 | </div> No newline at end of file | |
|
34 | </div> | |
|
35 | ||
|
36 | <% if authorize_for('wiki', 'add_attachment') %> | |
|
37 | <p><%= toggle_link l(:label_attachment_new), "add_attachment_form" %></p> | |
|
38 | <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :class => "tabular", :id => "add_attachment_form", :style => "display:none;") do %> | |
|
39 | <%= render :partial => 'attachments/form' %> | |
|
40 | <%= submit_tag l(:button_add) %> | |
|
41 | <% end %> | |
|
42 | <% end %> |
@@ -475,7 +475,8 position: relative; | |||
|
475 | 475 | margin: 0 5px 5px; |
|
476 | 476 | } |
|
477 | 477 | |
|
478 | div.attachments {padding-left: 6px; border-left: 2px solid #ccc;} | |
|
478 | div.attachments {padding-left: 6px; border-left: 2px solid #ccc; margin-bottom: 8px;} | |
|
479 | div.attachments p {margin-bottom:2px;} | |
|
479 | 480 | |
|
480 | 481 | .overlay{ |
|
481 | 482 | position: absolute; |
General Comments 0
You need to be logged in to leave comments.
Login now