##// END OF EJS Templates
Show last update datetime (last attachment added) on document list (#4232)....
Jean-Philippe Lang -
r2981:43fd27fd0ce4
parent child
Show More
@@ -1,88 +1,88
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class DocumentsController < ApplicationController
18 class DocumentsController < ApplicationController
19 default_search_scope :documents
19 default_search_scope :documents
20 before_filter :find_project, :only => [:index, :new]
20 before_filter :find_project, :only => [:index, :new]
21 before_filter :find_document, :except => [:index, :new]
21 before_filter :find_document, :except => [:index, :new]
22 before_filter :authorize
22 before_filter :authorize
23
23
24 helper :attachments
24 helper :attachments
25
25
26 def index
26 def index
27 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
27 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
28 documents = @project.documents.find :all, :include => [:attachments, :category]
28 documents = @project.documents.find :all, :include => [:attachments, :category]
29 case @sort_by
29 case @sort_by
30 when 'date'
30 when 'date'
31 @grouped = documents.group_by {|d| d.created_on.to_date }
31 @grouped = documents.group_by {|d| d.updated_on.to_date }
32 when 'title'
32 when 'title'
33 @grouped = documents.group_by {|d| d.title.first.upcase}
33 @grouped = documents.group_by {|d| d.title.first.upcase}
34 when 'author'
34 when 'author'
35 @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author}
35 @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author}
36 else
36 else
37 @grouped = documents.group_by(&:category)
37 @grouped = documents.group_by(&:category)
38 end
38 end
39 @document = @project.documents.build
39 @document = @project.documents.build
40 render :layout => false if request.xhr?
40 render :layout => false if request.xhr?
41 end
41 end
42
42
43 def show
43 def show
44 @attachments = @document.attachments.find(:all, :order => "created_on DESC")
44 @attachments = @document.attachments.find(:all, :order => "created_on DESC")
45 end
45 end
46
46
47 def new
47 def new
48 @document = @project.documents.build(params[:document])
48 @document = @project.documents.build(params[:document])
49 if request.post? and @document.save
49 if request.post? and @document.save
50 attach_files(@document, params[:attachments])
50 attach_files(@document, params[:attachments])
51 flash[:notice] = l(:notice_successful_create)
51 flash[:notice] = l(:notice_successful_create)
52 redirect_to :action => 'index', :project_id => @project
52 redirect_to :action => 'index', :project_id => @project
53 end
53 end
54 end
54 end
55
55
56 def edit
56 def edit
57 @categories = DocumentCategory.all
57 @categories = DocumentCategory.all
58 if request.post? and @document.update_attributes(params[:document])
58 if request.post? and @document.update_attributes(params[:document])
59 flash[:notice] = l(:notice_successful_update)
59 flash[:notice] = l(:notice_successful_update)
60 redirect_to :action => 'show', :id => @document
60 redirect_to :action => 'show', :id => @document
61 end
61 end
62 end
62 end
63
63
64 def destroy
64 def destroy
65 @document.destroy
65 @document.destroy
66 redirect_to :controller => 'documents', :action => 'index', :project_id => @project
66 redirect_to :controller => 'documents', :action => 'index', :project_id => @project
67 end
67 end
68
68
69 def add_attachment
69 def add_attachment
70 attachments = attach_files(@document, params[:attachments])
70 attachments = attach_files(@document, params[:attachments])
71 Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added')
71 Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added')
72 redirect_to :action => 'show', :id => @document
72 redirect_to :action => 'show', :id => @document
73 end
73 end
74
74
75 private
75 private
76 def find_project
76 def find_project
77 @project = Project.find(params[:project_id])
77 @project = Project.find(params[:project_id])
78 rescue ActiveRecord::RecordNotFound
78 rescue ActiveRecord::RecordNotFound
79 render_404
79 render_404
80 end
80 end
81
81
82 def find_document
82 def find_document
83 @document = Document.find(params[:id])
83 @document = Document.find(params[:id])
84 @project = @document.project
84 @project = @document.project
85 rescue ActiveRecord::RecordNotFound
85 rescue ActiveRecord::RecordNotFound
86 render_404
86 render_404
87 end
87 end
88 end
88 end
@@ -1,37 +1,45
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Document < ActiveRecord::Base
18 class Document < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
20 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
21 acts_as_attachable :delete_permission => :manage_documents
21 acts_as_attachable :delete_permission => :manage_documents
22
22
23 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
23 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
24 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
24 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
25 :author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
25 :author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
26 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
26 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
27 acts_as_activity_provider :find_options => {:include => :project}
27 acts_as_activity_provider :find_options => {:include => :project}
28
28
29 validates_presence_of :project, :title, :category
29 validates_presence_of :project, :title, :category
30 validates_length_of :title, :maximum => 60
30 validates_length_of :title, :maximum => 60
31
31
32 def after_initialize
32 def after_initialize
33 if new_record?
33 if new_record?
34 self.category ||= DocumentCategory.default
34 self.category ||= DocumentCategory.default
35 end
35 end
36 end
36 end
37
38 def updated_on
39 unless @updated_on
40 a = attachments.find(:first, :order => 'created_on DESC')
41 @updated_on = (a && a.created_on) || created_on
42 end
43 @updated_on
44 end
37 end
45 end
@@ -1,3 +1,3
1 <p><%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %><br />
1 <p><%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %><br />
2 <% unless document.description.blank? %><%=h(truncate(document.description, :length => 250)) %><br /><% end %>
2 <% unless document.description.blank? %><%=h(truncate(document.description, :length => 250)) %><br /><% end %>
3 <em><%= format_time(document.created_on) %></em></p> No newline at end of file
3 <em><%= format_time(document.updated_on) %></em></p> No newline at end of file
@@ -1,124 +1,136
1 ---
1 ---
2 attachments_001:
2 attachments_001:
3 created_on: 2006-07-19 21:07:27 +02:00
3 created_on: 2006-07-19 21:07:27 +02:00
4 downloads: 0
4 downloads: 0
5 content_type: text/plain
5 content_type: text/plain
6 disk_filename: 060719210727_error281.txt
6 disk_filename: 060719210727_error281.txt
7 container_id: 3
7 container_id: 3
8 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
8 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
9 id: 1
9 id: 1
10 container_type: Issue
10 container_type: Issue
11 filesize: 28
11 filesize: 28
12 filename: error281.txt
12 filename: error281.txt
13 author_id: 2
13 author_id: 2
14 attachments_002:
14 attachments_002:
15 created_on: 2006-07-19 21:07:27 +02:00
15 created_on: 2007-01-27 15:08:27 +01:00
16 downloads: 0
16 downloads: 0
17 content_type: text/plain
17 content_type: text/plain
18 disk_filename: 060719210727_document.txt
18 disk_filename: 060719210727_document.txt
19 container_id: 1
19 container_id: 1
20 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
20 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
21 id: 2
21 id: 2
22 container_type: Document
22 container_type: Document
23 filesize: 28
23 filesize: 28
24 filename: document.txt
24 filename: document.txt
25 author_id: 2
25 author_id: 2
26 attachments_003:
26 attachments_003:
27 created_on: 2006-07-19 21:07:27 +02:00
27 created_on: 2006-07-19 21:07:27 +02:00
28 downloads: 0
28 downloads: 0
29 content_type: image/gif
29 content_type: image/gif
30 disk_filename: 060719210727_logo.gif
30 disk_filename: 060719210727_logo.gif
31 container_id: 4
31 container_id: 4
32 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
32 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
33 id: 3
33 id: 3
34 container_type: WikiPage
34 container_type: WikiPage
35 filesize: 280
35 filesize: 280
36 filename: logo.gif
36 filename: logo.gif
37 description: This is a logo
37 description: This is a logo
38 author_id: 2
38 author_id: 2
39 attachments_004:
39 attachments_004:
40 created_on: 2006-07-19 21:07:27 +02:00
40 created_on: 2006-07-19 21:07:27 +02:00
41 container_type: Issue
41 container_type: Issue
42 container_id: 3
42 container_id: 3
43 downloads: 0
43 downloads: 0
44 disk_filename: 060719210727_source.rb
44 disk_filename: 060719210727_source.rb
45 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
45 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
46 id: 4
46 id: 4
47 filesize: 153
47 filesize: 153
48 filename: source.rb
48 filename: source.rb
49 author_id: 2
49 author_id: 2
50 description: This is a Ruby source file
50 description: This is a Ruby source file
51 content_type: application/x-ruby
51 content_type: application/x-ruby
52 attachments_005:
52 attachments_005:
53 created_on: 2006-07-19 21:07:27 +02:00
53 created_on: 2006-07-19 21:07:27 +02:00
54 container_type: Issue
54 container_type: Issue
55 container_id: 3
55 container_id: 3
56 downloads: 0
56 downloads: 0
57 disk_filename: 060719210727_changeset.diff
57 disk_filename: 060719210727_changeset.diff
58 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
58 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
59 id: 5
59 id: 5
60 filesize: 687
60 filesize: 687
61 filename: changeset.diff
61 filename: changeset.diff
62 author_id: 2
62 author_id: 2
63 content_type: text/x-diff
63 content_type: text/x-diff
64 attachments_006:
64 attachments_006:
65 created_on: 2006-07-19 21:07:27 +02:00
65 created_on: 2006-07-19 21:07:27 +02:00
66 container_type: Issue
66 container_type: Issue
67 container_id: 3
67 container_id: 3
68 downloads: 0
68 downloads: 0
69 disk_filename: 060719210727_archive.zip
69 disk_filename: 060719210727_archive.zip
70 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
70 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
71 id: 6
71 id: 6
72 filesize: 157
72 filesize: 157
73 filename: archive.zip
73 filename: archive.zip
74 author_id: 2
74 author_id: 2
75 content_type: application/octet-stream
75 content_type: application/octet-stream
76 attachments_007:
76 attachments_007:
77 created_on: 2006-07-19 21:07:27 +02:00
77 created_on: 2006-07-19 21:07:27 +02:00
78 container_type: Issue
78 container_type: Issue
79 container_id: 4
79 container_id: 4
80 downloads: 0
80 downloads: 0
81 disk_filename: 060719210727_archive.zip
81 disk_filename: 060719210727_archive.zip
82 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
82 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
83 id: 7
83 id: 7
84 filesize: 157
84 filesize: 157
85 filename: archive.zip
85 filename: archive.zip
86 author_id: 1
86 author_id: 1
87 content_type: application/octet-stream
87 content_type: application/octet-stream
88 attachments_008:
88 attachments_008:
89 created_on: 2006-07-19 21:07:27 +02:00
89 created_on: 2006-07-19 21:07:27 +02:00
90 container_type: Project
90 container_type: Project
91 container_id: 1
91 container_id: 1
92 downloads: 0
92 downloads: 0
93 disk_filename: 060719210727_project_file.zip
93 disk_filename: 060719210727_project_file.zip
94 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
94 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
95 id: 8
95 id: 8
96 filesize: 320
96 filesize: 320
97 filename: project_file.zip
97 filename: project_file.zip
98 author_id: 2
98 author_id: 2
99 content_type: application/octet-stream
99 content_type: application/octet-stream
100 attachments_009:
100 attachments_009:
101 created_on: 2006-07-19 21:07:27 +02:00
101 created_on: 2006-07-19 21:07:27 +02:00
102 container_type: Version
102 container_type: Version
103 container_id: 1
103 container_id: 1
104 downloads: 0
104 downloads: 0
105 disk_filename: 060719210727_version_file.zip
105 disk_filename: 060719210727_version_file.zip
106 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
106 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
107 id: 9
107 id: 9
108 filesize: 452
108 filesize: 452
109 filename: version_file.zip
109 filename: version_file.zip
110 author_id: 2
110 author_id: 2
111 content_type: application/octet-stream
111 content_type: application/octet-stream
112 attachments_010:
112 attachments_010:
113 created_on: 2006-07-19 21:07:27 +02:00
113 created_on: 2006-07-19 21:07:27 +02:00
114 container_type: Issue
114 container_type: Issue
115 container_id: 2
115 container_id: 2
116 downloads: 0
116 downloads: 0
117 disk_filename: 060719210727_picture.jpg
117 disk_filename: 060719210727_picture.jpg
118 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
118 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
119 id: 10
119 id: 10
120 filesize: 452
120 filesize: 452
121 filename: picture.jpg
121 filename: picture.jpg
122 author_id: 2
122 author_id: 2
123 content_type: image/jpeg
123 content_type: image/jpeg
124 attachments_011:
125 created_on: 2007-02-12 15:08:27 +01:00
126 container_type: Document
127 container_id: 1
128 downloads: 0
129 disk_filename: 060719210727_picture.jpg
130 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
131 id: 11
132 filesize: 452
133 filename: picture.jpg
134 author_id: 2
135 content_type: image/jpeg
124 No newline at end of file
136
@@ -1,7 +1,14
1 documents_001:
1 documents_001:
2 created_on: 2007-01-27 15:08:27 +01:00
2 created_on: 2007-01-27 15:08:27 +01:00
3 project_id: 1
3 project_id: 1
4 title: "Test document"
4 title: "Test document"
5 id: 1
5 id: 1
6 description: "Document description"
6 description: "Document description"
7 category_id: 1 No newline at end of file
7 category_id: 1
8 documents_002:
9 created_on: 2007-02-12 15:08:27 +01:00
10 project_id: 1
11 title: "An other document"
12 id: 2
13 description: ""
14 category_id: 2 No newline at end of file
@@ -1,46 +1,58
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19
19
20 class DocumentTest < ActiveSupport::TestCase
20 class DocumentTest < ActiveSupport::TestCase
21 fixtures :projects, :enumerations, :documents
21 fixtures :projects, :enumerations, :documents, :attachments
22
22
23 def test_create
23 def test_create
24 doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
24 doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
25 assert doc.save
25 assert doc.save
26 end
26 end
27
27
28 def test_create_should_send_email_notification
28 def test_create_should_send_email_notification
29 ActionMailer::Base.deliveries.clear
29 ActionMailer::Base.deliveries.clear
30 Setting.notified_events << 'document_added'
30 Setting.notified_events << 'document_added'
31 doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
31 doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation'))
32
32
33 assert doc.save
33 assert doc.save
34 assert_equal 1, ActionMailer::Base.deliveries.size
34 assert_equal 1, ActionMailer::Base.deliveries.size
35 end
35 end
36
36
37 def test_create_with_default_category
37 def test_create_with_default_category
38 # Sets a default category
38 # Sets a default category
39 e = Enumeration.find_by_name('Technical documentation')
39 e = Enumeration.find_by_name('Technical documentation')
40 e.update_attributes(:is_default => true)
40 e.update_attributes(:is_default => true)
41
41
42 doc = Document.new(:project => Project.find(1), :title => 'New document')
42 doc = Document.new(:project => Project.find(1), :title => 'New document')
43 assert_equal e, doc.category
43 assert_equal e, doc.category
44 assert doc.save
44 assert doc.save
45 end
45 end
46
47 def test_updated_on_with_attachments
48 d = Document.find(1)
49 assert d.attachments.any?
50 assert_equal d.attachments.map(&:created_on).max, d.updated_on
51 end
52
53 def test_updated_on_without_attachments
54 d = Document.find(2)
55 assert d.attachments.empty?
56 assert_equal d.created_on, d.updated_on
57 end
46 end
58 end
General Comments 0
You need to be logged in to leave comments. Login now