THIS PATCH REQUIRES A MIGRATION.
Added a column to projects for the project logo name.
Injected a default project logo name into the config_properties table.
The entry's name is "image.default_project_logo".
For now all projects have the same logo. Uploading will be handled in a
future sprint.
In the project list page the project logo is shown next to the name and
description.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/models/config_property.rb | 9 ++++
app/models/project.rb | 8 ++++
app/views/projects/index.html.erb | 1 +
app/views/projects/show.html.erb | 42 +++++++++++--------
db/migrate/032_add_logo_to_projects.rb | 26 ++++++++++++
.../033_create_default_project_logo_property.rb | 26 ++++++++++++
public/images/project.png | Bin 0 -> 18702 bytes
public/stylesheets/details.css | 9 ++++
test/fixtures/projects.yml | 1 +
test/unit/project_test.rb | 17 ++++++++
10 files changed, 121 insertions(+), 18 deletions(-)
create mode 100644 db/migrate/032_add_logo_to_projects.rb
create mode 100644 db/migrate/033_create_default_project_logo_property.rb
create mode 100644 public/images/project.png
diff --git a/app/models/config_property.rb b/app/models/config_property.rb
index 85255e7..107f630 100644
--- a/app/models/config_property.rb
+++ b/app/models/config_property.rb
@@ -57,4 +57,13 @@ class ConfigProperty < ActiveRecord::Base
ConfigProperty.create(:name => name, :value => value)
end
end
+
+ # Removes a configuration value.
+ def self.remove(name)
+ raise Exception.new("Missing property name") unless name &&
!name.empty?
+
+ property = ConfigProperty.find_by_name(name)
+
+ property.destroy if property
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 0eec2fb..f641431 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -15,6 +15,8 @@
# this program. If not, see <
http://www.gnu.org/licenses/>.
#
+require 'avatar'
+
# +Project+ represents a overall project. Projects are composed of one or more
# +Product+s, each of which produces an artifact.
#
@@ -54,4 +56,10 @@ class Project < ActiveRecord::Base
def can_approve?(user)
(user != nil) && user.privileges.admin_projects
end
+
+ # Returns the project logo URL.
+ def logo_url
+ return ConfigProperty.fetch("image.default_project_logo") unless logo_name
+ gravatar_url(logo_name)
+ end
end
diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb
index cf0fbb3..85fc6e2 100644
--- a/app/views/projects/index.html.erb
+++ b/app/views/projects/index.html.erb
@@ -20,6 +20,7 @@
<tr class="<%= cycle('odd', 'even') %>">
<td><%= project.id %></td>
<td class="name">
+ <div class="small-icon"><%= image_tag project.logo_url
%></div>
<%= link_to project.name, project_path(project) %>
<% if project.description %>
<%= RedCloth.new(get_first_sentence(project.description)).to_html %>
diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb
index 440a1cc..b8ca717 100644
--- a/app/views/projects/show.html.erb
+++ b/app/views/projects/show.html.erb
@@ -1,25 +1,31 @@
<div id="content">
<div id="page-details">
- <dl>
- <dt>Owner</dt>
- <dd><%= link_to @project.owner.display_name, user_path((a)project.owner)
%></dd>
+ <div id="logo">
+ <%= image_tag @project.logo_url %>
+ </div>
- <dt>Project homepage</dt>
- <dd>
- <% if @project.url %>
- <%= link_to @project.url, @project.url %>
- <% else %>
- Not provided.
- <% end %>
- </dd>
+ <div>
+ <dl>
+ <dt>Owner</dt>
+ <dd><%= link_to @project.owner.display_name, user_path((a)project.owner)
%></dd>
- <dt>Description</dt>
- <dd>
- <% if @project.description %>
- <%= RedCloth.new((a)project.description).to_html %>
- <% end %>
- </dd>
- </dl>
+ <dt>Project homepage</dt>
+ <dd>
+ <% if @project.url %>
+ <%= link_to @project.url, @project.url %>
+ <% else %>
+ Not provided.
+ <% end %>
+ </dd>
+
+ <dt>Description</dt>
+ <dd>
+ <% if @project.description %>
+ <%= RedCloth.new((a)project.description).to_html %>
+ <% end %>
+ </dd>
+ </dl>
+ </div>
</div>
</div>
diff --git a/db/migrate/032_add_logo_to_projects.rb
b/db/migrate/032_add_logo_to_projects.rb
new file mode 100644
index 0000000..dbe907a
--- /dev/null
+++ b/db/migrate/032_add_logo_to_projects.rb
@@ -0,0 +1,26 @@
+# 032_add_logo_to_projects.rb
+# Copyright (C) 2009, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <
http://www.gnu.org/licenses/>.
+#
+
+class AddLogoToProjects < ActiveRecord::Migration
+ def self.up
+ add_column :projects, :logo_name, :string, :limit => 255, :null => true,
:default => nil
+ end
+
+ def self.down
+ remove_column :projects, :logo_name
+ end
+end
diff --git a/db/migrate/033_create_default_project_logo_property.rb
b/db/migrate/033_create_default_project_logo_property.rb
new file mode 100644
index 0000000..ad575c6
--- /dev/null
+++ b/db/migrate/033_create_default_project_logo_property.rb
@@ -0,0 +1,26 @@
+# 033_create_default_project_logo_property
+# Copyright (C) 2009, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <
http://www.gnu.org/licenses/>.
+#
+
+class CreateDefaultProjectLogoProperty < ActiveRecord::Migration
+ def self.up
+ ConfigProperty.store("image.default_project_logo",
"/images/project.png")
+ end
+
+ def self.down
+ ConfigProperty.remove("image.default_project_log")
+ end
+end
diff --git a/public/images/project.png b/public/images/project.png
new file mode 100644
index 0000000000000000000000000000000000000000..059fd5df058c848df584fbfc037e7a024228d10d
GIT binary patch
literal 18702
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%0D7{rCmt`Uh)V
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
literal 0
HcmV?d00001
diff --git a/public/stylesheets/details.css b/public/stylesheets/details.css
index e6b4890..bd8e2f8 100644
--- a/public/stylesheets/details.css
+++ b/public/stylesheets/details.css
@@ -3,6 +3,15 @@
margin: 5px;
}
+#page-details div#logo {
+ float: right;
+}
+
+page-details logo img {
+ max-height: 64px;
+ max-weight: 64px;
+}
+
#page-details dt {
text-transform: uppercase;
font-size: larger;
diff --git a/test/fixtures/projects.yml b/test/fixtures/projects.yml
index 0929cfc..3733bcf 100644
--- a/test/fixtures/projects.yml
+++ b/test/fixtures/projects.yml
@@ -4,6 +4,7 @@ projxp:
url:
http://cairo.tigris.org/
description: An agile project management system using Scrum.
approved: true
+ logo_name: projxp.png
teatime:
owner_id: <%= Fixtures.identify(:teatime_owner) %>
diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb
index 71e356c..4d1d314 100644
--- a/test/unit/project_test.rb
+++ b/test/unit/project_test.rb
@@ -35,6 +35,11 @@ class ProjectTest < ActiveSupport::TestCase
@nonadmin = users(:mcpierce)
raise "Nonadmin must not have project admin rights!" if
@nonadmin.privileges.admin_projects
+ @project_with_logo = projects(:projxp)
+ raise "Project must have a logo!" unless @project_with_logo.logo_name
+ @project_without_logo = projects(:teatime)
+ raise "Project must not have a logo!" if @project_without_logo.logo_name
+
@new_project = Project.new(
:name => "New Projects",
:owner_id => @nonowner.id,
@@ -106,4 +111,16 @@ class ProjectTest < ActiveSupport::TestCase
def test_create_epics
flunk "A project owner can create epics." unless
@existing_project.can_create_epics?(@owner)
end
+
+ # Ensures that a project with no logo returns the default logo.
+ def test_logo_url_for_project_with_no_logo
+ expected = ConfigProperty.fetch("image.default_project_logo")
+ assert_equal expected, @project_without_logo.logo_url, "The default URL is not
correct."
+ end
+
+ # Ensures that a project with a logo returns the right logo URL.
+ def test_logo_url
+ expected = gravatar_url((a)project_with_logo.logo_name)
+ assert_equal expected, @project_with_logo.logo_url, "The generated logo is not
correct."
+ end
end
--
1.6.0.6