[PATCH] Mailer configuration is moved to the database. #124
by Darryl L. Pierce
This patch requires a migration. It introduces a new database, called
config_properties, that holds site configuration details. It also adds
a new column to the user_privileges table called site_admin. Users with
this privilege are able to access and change site configuration
properties.
A configuration property is composed of a name and a value. Names are
hierarchical is nature, with each segment separated by a period (.). So,
for example, the email server name is "email.server.name".
This patch moves the content of config/mailer.yml to the database.
To access the configuration, the user goes to /admin/email. The new controller,
EmailController, extends the equally new AdminController. All administration
controllers must extend this base class to inherit admin functionality.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/admin_controller.rb | 48 +++++++++
app/controllers/application.rb | 1 +
app/controllers/emails_controller.rb | 62 +++++++++++
app/helpers/admin_helper.rb | 2 +
app/helpers/emails_helper.rb | 19 ++++
app/models/config_property.rb | 31 ++++++
app/models/user_mailer.rb | 18 ++--
app/views/emails/edit.html.erb | 26 +++++
app/views/emails/show.html.erb | 33 ++++++
app/views/emails/show.html.erb~ | 2 +
app/views/sprints/plan.html.erb | 6 +-
config/initializers/mailer.rb | 35 ++++---
config/mailer.yml.example | 12 --
config/routes.rb | 3 +
.../023_add_admin_site_to_user_privileges.rb | 33 ++++++
db/migrate/024_create_config_properties.rb | 31 ++++++
db/schema.rb | 10 ++-
public/stylesheets/forms.css | 2 -
test/fixtures/config_properties.yml | 3 +
test/fixtures/user_privileges.yml | 1 +
test/functional/admin_controller_test.rb | 8 ++
test/functional/emails_controller_test.rb | 108 ++++++++++++++++++++
test/unit/config_property_test.rb | 46 ++++++++
23 files changed, 497 insertions(+), 43 deletions(-)
create mode 100644 app/controllers/admin_controller.rb
create mode 100644 app/controllers/emails_controller.rb
create mode 100644 app/helpers/admin_helper.rb
create mode 100644 app/helpers/emails_helper.rb
create mode 100644 app/models/config_property.rb
create mode 100644 app/views/emails/edit.html.erb
create mode 100644 app/views/emails/show.html.erb
create mode 100644 app/views/emails/show.html.erb~
delete mode 100644 config/mailer.yml.example
create mode 100644 db/migrate/023_add_admin_site_to_user_privileges.rb
create mode 100644 db/migrate/024_create_config_properties.rb
create mode 100644 test/fixtures/config_properties.yml
create mode 100644 test/functional/admin_controller_test.rb
create mode 100644 test/functional/emails_controller_test.rb
create mode 100644 test/unit/config_property_test.rb
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
new file mode 100644
index 0000000..2075f4f
--- /dev/null
+++ b/app/controllers/admin_controller.rb
@@ -0,0 +1,48 @@
+# admin_controller_test.rb
+# Copyright (C) 2008, 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 AdminController < ApplicationController
+ before_filter :authenticated
+ before_filter :authorized
+
+ private
+
+ def authorized
+ unless @user && @user.privileges.admin_site
+ flash[:message] = "You do not have administrative rights to this system."
+ respond_to do |format|
+ format.html { redirect_to error_path }
+ end
+ end
+ end
+
+ # Loads specific properties formthe database
+ def load_properties(names)
+ result = Hash.new
+
+ names.each do |name|
+ property = ConfigProperty.find_by_name(name)
+ if property
+ result["#{name}"] = property.value
+ else
+ result["#{name}"] = ''
+ end
+ end
+
+ return result
+ end
+end
diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index d318bad..cc4aecc 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -59,6 +59,7 @@ class ApplicationController < ActionController::Base
def handle_exceptions
yield
rescue Exception => error
+ puts "CAUSE EXCEPTION: #{error.message}"
puts error.backtrace
erase_results
@title = "An Error Has Occurred."
diff --git a/app/controllers/emails_controller.rb b/app/controllers/emails_controller.rb
new file mode 100644
index 0000000..bfd2ef7
--- /dev/null
+++ b/app/controllers/emails_controller.rb
@@ -0,0 +1,62 @@
+# emails_controller.rb
+# Copyright (C) 2008, 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/>.
+#
+
+# +EmailsController+ allows administrators to administer the email system for the
+# server.
+class EmailsController < AdminController
+ EMAIL_PROPERTIES = ['email.server.type',
+ 'email.server.smtp_tls',
+ 'email.server.perform_deliveries',
+ 'email.server.name',
+ 'email.server.port',
+ 'email.server.auth_mode',
+ 'email.server.username',
+ 'email.server.password',
+ 'email.from_address'
+ ]
+
+ # GET /admin/email
+ def show
+ @properties = load_properties(EMAIL_PROPERTIES)
+ end
+
+ # GET /admin/email/edit
+ def edit
+ @properties = load_properties(EMAIL_PROPERTIES)
+ end
+
+ # PUT /admin/email
+ def update
+ @properties = params[:properties]
+
+ ConfigProperty.transaction do
+ EMAIL_PROPERTIES.each do |property|
+ config_property = ConfigProperty.find_by_name(property) || ConfigProperty.new(:name => property)
+ config_property.value = (@properties[property] || '').strip
+
+ config_property.save!
+ end
+ end
+
+ # restart the email service
+ load_email_config
+
+ respond_to do |format|
+ format.html { redirect_to admin_email_path }
+ end
+ end
+end
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
new file mode 100644
index 0000000..d5c6d35
--- /dev/null
+++ b/app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
new file mode 100644
index 0000000..694790c
--- /dev/null
+++ b/app/helpers/emails_helper.rb
@@ -0,0 +1,19 @@
+# emails_helper.rb
+# Copyright (C) 2008, 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/>.
+#
+
+module EmailsHelper
+end
diff --git a/app/models/config_property.rb b/app/models/config_property.rb
new file mode 100644
index 0000000..ad0265e
--- /dev/null
+++ b/app/models/config_property.rb
@@ -0,0 +1,31 @@
+# config_property.rb
+# Copyright (C) 2008, 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/>.
+#
+
+# A +ConfigProperty+ represents a single configuration value.
+class ConfigProperty < ActiveRecord::Base
+ validates_presence_of :name,
+ :message => "A configuration property must have a name."
+ validates_uniqueness_of :name,
+ :message => "Configuration property names must be unique."
+
+ def self.value_by_name(name)
+ property = ConfigProperty.find_by_name(name)
+
+ return property.value if property
+ return ''
+ end
+end
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 5609dc8..734b820 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -19,7 +19,7 @@ class UserMailer < ActionMailer::Base
# Sends an email verification to the specified user.
def email_verification(user, token)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Email verification"
body :user => user, :token => token
end
@@ -27,7 +27,7 @@ class UserMailer < ActionMailer::Base
# Sends an email to the old address when the user changes his email address.
def email_change_notification(user, old_email)
recipients old_email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Email change notification"
body :user => user, :old_email => old_email
end
@@ -35,7 +35,7 @@ class UserMailer < ActionMailer::Base
# Send an e-mail to an user and notify him his new password.
def new_generated_password(user, new_password)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Your password"
body :user => user, :new_password => new_password
end
@@ -43,7 +43,7 @@ class UserMailer < ActionMailer::Base
# Sends an email to a product owner when a user requests a product role.
def product_role_request(requested_role)
recipients requested_role.product.owner.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Role request for #{requested_role.product.name}..."
body :requested_role => requested_role
end
@@ -52,7 +52,7 @@ class UserMailer < ActionMailer::Base
# product role request.
def product_role_disposition(role)
recipients role.user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Role request status..."
body :role => role
end
@@ -61,7 +61,7 @@ class UserMailer < ActionMailer::Base
def daily_updates(user, cc_list, open_items, completed_items, task_performed)
recipients user.email
cc cc_list
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Daily updates for #{user.display_name}"
body :user => user, :open_items => open_items,
:completed_items => completed_items, :tasks_performed => task_performed
@@ -71,7 +71,7 @@ class UserMailer < ActionMailer::Base
# his backlog.
def no_activity_recorded(user, backlog_items)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "No activity has been detected"
body :user => user, :backlog_items => backlog_items
end
@@ -80,7 +80,7 @@ class UserMailer < ActionMailer::Base
# backlog.
def no_task_recorded(user, backlog_items)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "No task has been detected"
body :user => user, :backlog_items => backlog_items
end
@@ -89,7 +89,7 @@ class UserMailer < ActionMailer::Base
# products.
def sprints_products_status(user, products)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Status of sprints"
body :user => user, :products => products
end
diff --git a/app/views/emails/edit.html.erb b/app/views/emails/edit.html.erb
new file mode 100644
index 0000000..ae27d80
--- /dev/null
+++ b/app/views/emails/edit.html.erb
@@ -0,0 +1,26 @@
+<% form_tag :admin_email, :method => :put do %>
+<table class="edit">
+ <colgroup>
+ <col class="label" />
+ <col class="value" />
+ </colgroup>
+
+ <tbody>
+ <% EmailsController::EMAIL_PROPERTIES.each do |property| %>
+ <tr>
+ <td class="label"><%= property %></td>
+ <td class="value">
+ <%= text_field_tag "properties[#{property}]",
+ @properties["#{property}"] %>
+ </td>
+ </tr>
+ <% end %>
+ <tr>
+ <td class="buttonbar" colspan="2">
+ <%= submit_tag "Update" %>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<% end %>
diff --git a/app/views/emails/show.html.erb b/app/views/emails/show.html.erb
new file mode 100644
index 0000000..416a628
--- /dev/null
+++ b/app/views/emails/show.html.erb
@@ -0,0 +1,33 @@
+<table class="detail">
+ <colgroup>
+ <col class="label" />
+ <col class="value" />
+ </colgroup>
+
+ <thead>
+ <tr>
+ <th class="title" colspan="2">Email Configuration</th>
+ </tr>
+ <tr>
+ <th class="toolbar" colspan="2">
+ <%= link_to(image_tag("icons/edit.png", :title => 'Edit email settings...'),
+ edit_admin_email_path) %>
+ </th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% EmailsController::EMAIL_PROPERTIES.each do |property| %>
+ <tr>
+ <td class="label"><%= "#{property}" %></td>
+ <td class="value">
+ <% unless (@properties[property]).empty? %>
+ <%= "#{@properties[property]}" %>
+ <% else %>
+ [UNDEFINED]
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
diff --git a/app/views/emails/show.html.erb~ b/app/views/emails/show.html.erb~
new file mode 100644
index 0000000..819ed4d
--- /dev/null
+++ b/app/views/emails/show.html.erb~
@@ -0,0 +1,2 @@
+<table class="detail">
+</table>
diff --git a/app/views/sprints/plan.html.erb b/app/views/sprints/plan.html.erb
index ace6139..34867b3 100644
--- a/app/views/sprints/plan.html.erb
+++ b/app/views/sprints/plan.html.erb
@@ -20,10 +20,8 @@
</thead>
<tbody>
- <% @user_stories.each_with_index do |story, index| %>
- <% row_class = index%2 == 0 ? 'even' : 'odd' %>
- <% backlog_item = @sprint.backlog_items.find_by_user_story_id(story.id) %>
- <tr class="<%= row_class %>">
+ <% @user_stories.each do |story| %>
+ <tr class="<%= cycle('odd', 'even') %>">
<td><%= story.id %></td>
<td><%= story.priority %></td>
<td>
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
index c41382b..21c47c4 100644
--- a/config/initializers/mailer.rb
+++ b/config/initializers/mailer.rb
@@ -14,21 +14,26 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-MAIL_CONFIG = YAML.load(File.open("#{RAILS_ROOT}/config/mailer.yml"))
-
require 'tlsmail'
-Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
-ActionMailer::Base.delivery_method = MAIL_CONFIG[:delivery_method]
-ActionMailer::Base.perform_deliveries = MAIL_CONFIG[:perform_deliveries]
-ActionMailer::Base.default_charset = MAIL_CONFIG[:default_charset]
-ActionMailer::Base.raise_delivery_errors = MAIL_CONFIG[:raise_delivery_errors]
+def load_email_config
+ puts "Reloading email configuration"
+ Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
+ ActionMailer::Base.delivery_method = ConfigProperty.value_by_name('email.server.type')
+ ActionMailer::Base.perform_deliveries = ConfigProperty.value_by_name('email.server.perform_deliveries')
+ ActionMailer::Base.default_charset = 'utf-8'
+ ActionMailer::Base.raise_delivery_errors = true
+
+ ActionMailer::Base.smtp_settings = {
+ :address => ConfigProperty.value_by_name('email.server.name'),
+ :port => ConfigProperty.value_by_name('email.server.port'),
+ :tls => ConfigProperty.value_by_name('email.server.smtp_tls'),
+ :authentication => ConfigProperty.value_by_name('email.server.auth_mode'),
+ :user_name => ConfigProperty.value_by_name('email.server.username'),
+ :password => ConfigProperty.value_by_name('email.server.password')
+ }
+
+ puts ActionMailer::Base.smtp_settings
+end
-ActionMailer::Base.smtp_settings = {
- :address => MAIL_CONFIG[:server_name],
- :port => MAIL_CONFIG[:server_port],
- :tls => MAIL_CONFIG[:require_smtp_tls],
- :authentication => MAIL_CONFIG[:server_auth_mode],
- :user_name => MAIL_CONFIG[:server_username],
- :password => MAIL_CONFIG[:server_password]
-}
+load_email_config
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
deleted file mode 100644
index 1dd4aa2..0000000
--- a/config/mailer.yml.example
+++ /dev/null
@@ -1,12 +0,0 @@
----
-:delivery_method: :smtp
-:require_smtp_tls: true
-:perform_deliveries: true
-:default_charset: utf-8
-:raise_delivery_errors: true
-:server_name: smtp.gmail.com
-:server_port: 587
-:server_auth_mode: :login
-:server_username: your_username
-:server_password: your_password
-:from: noreply(a)projxp.org
diff --git a/config/routes.rb b/config/routes.rb
index 6ae69bc..c5df8ce 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -16,6 +16,9 @@
#
ActionController::Routing::Routes.draw do |map|
+ map.resource :admin, :plural => :admin do |admin|
+ admin.resource :email, :plural => :email
+ end
map.resources :projects
map.resources :products do |product|
product.resources :roles
diff --git a/db/migrate/023_add_admin_site_to_user_privileges.rb b/db/migrate/023_add_admin_site_to_user_privileges.rb
new file mode 100644
index 0000000..565f414
--- /dev/null
+++ b/db/migrate/023_add_admin_site_to_user_privileges.rb
@@ -0,0 +1,33 @@
+# 023_add_admin_site_to_user_privileges.rb
+# Copyright (C) 2008, 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 AddAdminSiteToUserPrivileges < ActiveRecord::Migration
+ def self.up
+ add_column :user_privileges, :admin_site, :boolean, :default => false
+
+ # make the admin account a site admin
+ privileges = UserPrivilege.find_by_user_id(1)
+ if privileges
+ privileges.admin_site = true
+ privileges.save!
+ end
+ end
+
+ def self.down
+ remove_column :user_privileges, :admin_site
+ end
+end
diff --git a/db/migrate/024_create_config_properties.rb b/db/migrate/024_create_config_properties.rb
new file mode 100644
index 0000000..5bcb87b
--- /dev/null
+++ b/db/migrate/024_create_config_properties.rb
@@ -0,0 +1,31 @@
+# 024_create_config_properties.rb
+# Copyright (C) 2008, 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 CreateConfigProperties < ActiveRecord::Migration
+ def self.up
+ create_table :config_properties do |t|
+ t.string :name, :null => false, :limit => 128
+ t.text :value, :null => true
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :config_properties
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index dc8868f..099266d 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 22) do
+ActiveRecord::Schema.define(:version => 24) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -24,6 +24,13 @@ ActiveRecord::Schema.define(:version => 22) do
add_index "backlog_items", ["sprint_id", "user_story_id"], :name => "index_backlog_items_on_sprint_id_and_user_story_id", :unique => true
+ create_table "config_properties", :force => true do |t|
+ t.string "name", :limit => 128, :null => false
+ t.text "value"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "notifications", :force => true do |t|
t.integer "user_id"
t.boolean "task_reminders"
@@ -125,6 +132,7 @@ ActiveRecord::Schema.define(:version => 22) do
t.boolean "admin_users", :default => false, :null => false
t.datetime "created_at"
t.datetime "updated_at"
+ t.boolean "admin_site", :default => false
end
create_table "user_stories", :force => true do |t|
diff --git a/public/stylesheets/forms.css b/public/stylesheets/forms.css
index 07dc248..51bcc2e 100644
--- a/public/stylesheets/forms.css
+++ b/public/stylesheets/forms.css
@@ -23,11 +23,9 @@ table.edit {
}
table.edit col.label {
- width: 15em;
}
table.edit col.value {
- width: 100%;
}
table.edit {
diff --git a/test/fixtures/config_properties.yml b/test/fixtures/config_properties.yml
new file mode 100644
index 0000000..b83d3d6
--- /dev/null
+++ b/test/fixtures/config_properties.yml
@@ -0,0 +1,3 @@
+mail_server_name:
+ name: email.server.name
+ value: smtp.gmail.com
diff --git a/test/fixtures/user_privileges.yml b/test/fixtures/user_privileges.yml
index 38ffbf7..ba57357 100644
--- a/test/fixtures/user_privileges.yml
+++ b/test/fixtures/user_privileges.yml
@@ -4,6 +4,7 @@ admin_privileges:
user_id: <%= Fixtures.identify(:admin) %>
admin_projects: true
admin_users: true
+ admin_site: true
projxp_owner_privileges:
user_id: <%= Fixtures.identify(:projxp_owner) %>
diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb
new file mode 100644
index 0000000..d4c1dd4
--- /dev/null
+++ b/test/functional/admin_controller_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class AdminControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/test/functional/emails_controller_test.rb b/test/functional/emails_controller_test.rb
new file mode 100644
index 0000000..86f4bca
--- /dev/null
+++ b/test/functional/emails_controller_test.rb
@@ -0,0 +1,108 @@
+# email_controller_test.rb
+# Copyright (C) 2008, 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/>.
+#
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class EmailsControllerTest < ActionController::TestCase
+ fixtures :users
+
+ def setup
+ @admin = users(:admin)
+ raise "Admin must have site admin rights." unless @admin.privileges.admin_site
+ @nonadmin = users(:mcpierce)
+ raise "Nonadmin cannot have site admin rights." if @nonadmin.privileges.admin_site
+ end
+
+ # Ensures that anonymous users cannot view the email configuration.
+ def test_show_as_anonymous
+ get :show
+
+ assert_redirected_to login_path
+ end
+
+ # Ensures that users who are not site admins cannot view the configuration.
+ def test_show_as_nonadmin
+ get :show, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that administrators can view the email configuration.
+ def test_show
+ get :show, {}, {:user_id => @admin.id}
+
+ assert_response :success
+ assert assigns['properties']
+ properties = assigns['properties']
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ assert properties["#{property}"], "Missing property: #{property}"
+ end
+ end
+
+ # Ensures that an anonymous user cannot access the edit email page.
+ def test_edit_as_anonymous
+ get :edit
+
+ assert_redirected_to login_url
+ end
+
+ # Ensures that a non-admin cannot access the edit page.
+ def test_edit_as_nonadmin
+ get :edit, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that an admin can edit the email settings.
+ def test_edit
+ get :edit, {}, {:user_id => @admin.id}
+
+ assert_response :success
+ end
+
+ # Ensures that an anonymous user cannot update the mail settings.
+ def test_update_as_anonymous
+ put :update
+
+ assert_redirected_to :login_url
+ end
+
+ # Ensures that a nonadmin cannot update the mail settings.
+ def test_update_as_nonadmin
+ put :update, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that updating works as expected.
+ def test_update
+ updates = Hash.new
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ updates[property] = property.reverse
+ end
+
+ put :update, {:properties => updates}, {:user_id => @admin.id}
+
+ assert_redirected_to admin_email_url
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ config_property = ConfigProperty.find_by_name(property)
+ assert config_property, "Property was not saved."
+ assert_equal updates[property], config_property.value,
+ "Value was not saved correctly."
+ end
+ end
+end
diff --git a/test/unit/config_property_test.rb b/test/unit/config_property_test.rb
new file mode 100644
index 0000000..98c305d
--- /dev/null
+++ b/test/unit/config_property_test.rb
@@ -0,0 +1,46 @@
+# config_property_test.rb
+# Copyright (C) 2008, 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/>.
+#
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ConfigPropertyTest < ActiveSupport::TestCase
+ def setup
+ @config_property = ConfigProperty.new(:name => 'name', :value => 'value')
+ @existing_property = config_properties(:mail_server_name)
+ end
+
+ # Ensures that a config property requires a name.
+ def test_name_required
+ @config_property.name = nil
+
+ fail "The name must be required." if @config_property.valid?
+ end
+
+ # Ensures that a config property name must be unique.
+ def test_name_unique
+ @config_property.name = @existing_property.name
+
+ fail "The name must be unique." if @config_property.valid?
+ end
+
+ # Ensures that a value does not need to be present.
+ def test_value_not_required
+ @config_property.value = nil
+
+ fail "The value is not required." unless @config_property.valid?
+ end
+end
--
1.6.0.2
15 years, 2 months
[PATCH] Mailer configuration is moved to the database. #124
by Darryl L. Pierce
This patch requires a migration. It introduces a new database, called
config_properties, that holds site configuration details. It also adds
a new column to the user_privileges table called site_admin. Users with
this privilege are able to access and change site configuration
properties.
A configuration property is composed of a name and a value. Names are
hierarchical is nature, with each segment separated by a period (.). So,
for example, the email server name is "email.server.name".
This patch moves the content of config/mailer.yml to the database.
To access the configuration, the user goes to /admin/email. The new controller,
EmailController, extends the equally new AdminController. All administration
controllers must extend this base class to inherit admin functionality.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/admin_controller.rb | 48 +++++++++
app/controllers/application.rb | 1 +
app/controllers/emails_controller.rb | 62 +++++++++++
app/helpers/admin_helper.rb | 2 +
app/helpers/emails_helper.rb | 19 ++++
app/models/config_property.rb | 31 ++++++
app/models/user_mailer.rb | 18 ++--
app/views/emails/edit.html.erb | 26 +++++
app/views/emails/show.html.erb | 33 ++++++
app/views/emails/show.html.erb~ | 2 +
app/views/sprints/plan.html.erb | 6 +-
config/initializers/mailer.rb | 35 ++++---
config/mailer.yml.example | 12 --
config/routes.rb | 3 +
.../023_add_admin_site_to_user_privileges.rb | 33 ++++++
db/migrate/024_create_config_properties.rb | 31 ++++++
db/schema.rb | 10 ++-
public/stylesheets/forms.css | 2 -
test/fixtures/config_properties.yml | 3 +
test/fixtures/user_privileges.yml | 1 +
test/functional/admin_controller_test.rb | 8 ++
test/functional/emails_controller_test.rb | 108 ++++++++++++++++++++
test/unit/config_property_test.rb | 46 ++++++++
23 files changed, 497 insertions(+), 43 deletions(-)
create mode 100644 app/controllers/admin_controller.rb
create mode 100644 app/controllers/emails_controller.rb
create mode 100644 app/helpers/admin_helper.rb
create mode 100644 app/helpers/emails_helper.rb
create mode 100644 app/models/config_property.rb
create mode 100644 app/views/emails/edit.html.erb
create mode 100644 app/views/emails/show.html.erb
create mode 100644 app/views/emails/show.html.erb~
delete mode 100644 config/mailer.yml.example
create mode 100644 db/migrate/023_add_admin_site_to_user_privileges.rb
create mode 100644 db/migrate/024_create_config_properties.rb
create mode 100644 test/fixtures/config_properties.yml
create mode 100644 test/functional/admin_controller_test.rb
create mode 100644 test/functional/emails_controller_test.rb
create mode 100644 test/unit/config_property_test.rb
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
new file mode 100644
index 0000000..2075f4f
--- /dev/null
+++ b/app/controllers/admin_controller.rb
@@ -0,0 +1,48 @@
+# admin_controller_test.rb
+# Copyright (C) 2008, 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 AdminController < ApplicationController
+ before_filter :authenticated
+ before_filter :authorized
+
+ private
+
+ def authorized
+ unless @user && @user.privileges.admin_site
+ flash[:message] = "You do not have administrative rights to this system."
+ respond_to do |format|
+ format.html { redirect_to error_path }
+ end
+ end
+ end
+
+ # Loads specific properties formthe database
+ def load_properties(names)
+ result = Hash.new
+
+ names.each do |name|
+ property = ConfigProperty.find_by_name(name)
+ if property
+ result["#{name}"] = property.value
+ else
+ result["#{name}"] = ''
+ end
+ end
+
+ return result
+ end
+end
diff --git a/app/controllers/application.rb b/app/controllers/application.rb
index dc59da1..58c473d 100644
--- a/app/controllers/application.rb
+++ b/app/controllers/application.rb
@@ -51,6 +51,7 @@ class ApplicationController < ActionController::Base
def handle_exceptions
yield
rescue Exception => error
+ puts "CAUSE EXCEPTION: #{error.message}"
puts error.backtrace
erase_results
@title = "An Error Has Occurred."
diff --git a/app/controllers/emails_controller.rb b/app/controllers/emails_controller.rb
new file mode 100644
index 0000000..bfd2ef7
--- /dev/null
+++ b/app/controllers/emails_controller.rb
@@ -0,0 +1,62 @@
+# emails_controller.rb
+# Copyright (C) 2008, 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/>.
+#
+
+# +EmailsController+ allows administrators to administer the email system for the
+# server.
+class EmailsController < AdminController
+ EMAIL_PROPERTIES = ['email.server.type',
+ 'email.server.smtp_tls',
+ 'email.server.perform_deliveries',
+ 'email.server.name',
+ 'email.server.port',
+ 'email.server.auth_mode',
+ 'email.server.username',
+ 'email.server.password',
+ 'email.from_address'
+ ]
+
+ # GET /admin/email
+ def show
+ @properties = load_properties(EMAIL_PROPERTIES)
+ end
+
+ # GET /admin/email/edit
+ def edit
+ @properties = load_properties(EMAIL_PROPERTIES)
+ end
+
+ # PUT /admin/email
+ def update
+ @properties = params[:properties]
+
+ ConfigProperty.transaction do
+ EMAIL_PROPERTIES.each do |property|
+ config_property = ConfigProperty.find_by_name(property) || ConfigProperty.new(:name => property)
+ config_property.value = (@properties[property] || '').strip
+
+ config_property.save!
+ end
+ end
+
+ # restart the email service
+ load_email_config
+
+ respond_to do |format|
+ format.html { redirect_to admin_email_path }
+ end
+ end
+end
diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb
new file mode 100644
index 0000000..d5c6d35
--- /dev/null
+++ b/app/helpers/admin_helper.rb
@@ -0,0 +1,2 @@
+module AdminHelper
+end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
new file mode 100644
index 0000000..694790c
--- /dev/null
+++ b/app/helpers/emails_helper.rb
@@ -0,0 +1,19 @@
+# emails_helper.rb
+# Copyright (C) 2008, 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/>.
+#
+
+module EmailsHelper
+end
diff --git a/app/models/config_property.rb b/app/models/config_property.rb
new file mode 100644
index 0000000..ad0265e
--- /dev/null
+++ b/app/models/config_property.rb
@@ -0,0 +1,31 @@
+# config_property.rb
+# Copyright (C) 2008, 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/>.
+#
+
+# A +ConfigProperty+ represents a single configuration value.
+class ConfigProperty < ActiveRecord::Base
+ validates_presence_of :name,
+ :message => "A configuration property must have a name."
+ validates_uniqueness_of :name,
+ :message => "Configuration property names must be unique."
+
+ def self.value_by_name(name)
+ property = ConfigProperty.find_by_name(name)
+
+ return property.value if property
+ return ''
+ end
+end
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 5609dc8..734b820 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -19,7 +19,7 @@ class UserMailer < ActionMailer::Base
# Sends an email verification to the specified user.
def email_verification(user, token)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Email verification"
body :user => user, :token => token
end
@@ -27,7 +27,7 @@ class UserMailer < ActionMailer::Base
# Sends an email to the old address when the user changes his email address.
def email_change_notification(user, old_email)
recipients old_email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Email change notification"
body :user => user, :old_email => old_email
end
@@ -35,7 +35,7 @@ class UserMailer < ActionMailer::Base
# Send an e-mail to an user and notify him his new password.
def new_generated_password(user, new_password)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Your password"
body :user => user, :new_password => new_password
end
@@ -43,7 +43,7 @@ class UserMailer < ActionMailer::Base
# Sends an email to a product owner when a user requests a product role.
def product_role_request(requested_role)
recipients requested_role.product.owner.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Role request for #{requested_role.product.name}..."
body :requested_role => requested_role
end
@@ -52,7 +52,7 @@ class UserMailer < ActionMailer::Base
# product role request.
def product_role_disposition(role)
recipients role.user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Role request status..."
body :role => role
end
@@ -61,7 +61,7 @@ class UserMailer < ActionMailer::Base
def daily_updates(user, cc_list, open_items, completed_items, task_performed)
recipients user.email
cc cc_list
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Daily updates for #{user.display_name}"
body :user => user, :open_items => open_items,
:completed_items => completed_items, :tasks_performed => task_performed
@@ -71,7 +71,7 @@ class UserMailer < ActionMailer::Base
# his backlog.
def no_activity_recorded(user, backlog_items)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "No activity has been detected"
body :user => user, :backlog_items => backlog_items
end
@@ -80,7 +80,7 @@ class UserMailer < ActionMailer::Base
# backlog.
def no_task_recorded(user, backlog_items)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "No task has been detected"
body :user => user, :backlog_items => backlog_items
end
@@ -89,7 +89,7 @@ class UserMailer < ActionMailer::Base
# products.
def sprints_products_status(user, products)
recipients user.email
- from MAIL_CONFIG[:from]
+ from ConfigProperty.value_by_name('email.from_address')
subject "Status of sprints"
body :user => user, :products => products
end
diff --git a/app/views/emails/edit.html.erb b/app/views/emails/edit.html.erb
new file mode 100644
index 0000000..ae27d80
--- /dev/null
+++ b/app/views/emails/edit.html.erb
@@ -0,0 +1,26 @@
+<% form_tag :admin_email, :method => :put do %>
+<table class="edit">
+ <colgroup>
+ <col class="label" />
+ <col class="value" />
+ </colgroup>
+
+ <tbody>
+ <% EmailsController::EMAIL_PROPERTIES.each do |property| %>
+ <tr>
+ <td class="label"><%= property %></td>
+ <td class="value">
+ <%= text_field_tag "properties[#{property}]",
+ @properties["#{property}"] %>
+ </td>
+ </tr>
+ <% end %>
+ <tr>
+ <td class="buttonbar" colspan="2">
+ <%= submit_tag "Update" %>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<% end %>
diff --git a/app/views/emails/show.html.erb b/app/views/emails/show.html.erb
new file mode 100644
index 0000000..416a628
--- /dev/null
+++ b/app/views/emails/show.html.erb
@@ -0,0 +1,33 @@
+<table class="detail">
+ <colgroup>
+ <col class="label" />
+ <col class="value" />
+ </colgroup>
+
+ <thead>
+ <tr>
+ <th class="title" colspan="2">Email Configuration</th>
+ </tr>
+ <tr>
+ <th class="toolbar" colspan="2">
+ <%= link_to(image_tag("icons/edit.png", :title => 'Edit email settings...'),
+ edit_admin_email_path) %>
+ </th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% EmailsController::EMAIL_PROPERTIES.each do |property| %>
+ <tr>
+ <td class="label"><%= "#{property}" %></td>
+ <td class="value">
+ <% unless (@properties[property]).empty? %>
+ <%= "#{@properties[property]}" %>
+ <% else %>
+ [UNDEFINED]
+ <% end %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
diff --git a/app/views/emails/show.html.erb~ b/app/views/emails/show.html.erb~
new file mode 100644
index 0000000..819ed4d
--- /dev/null
+++ b/app/views/emails/show.html.erb~
@@ -0,0 +1,2 @@
+<table class="detail">
+</table>
diff --git a/app/views/sprints/plan.html.erb b/app/views/sprints/plan.html.erb
index ace6139..34867b3 100644
--- a/app/views/sprints/plan.html.erb
+++ b/app/views/sprints/plan.html.erb
@@ -20,10 +20,8 @@
</thead>
<tbody>
- <% @user_stories.each_with_index do |story, index| %>
- <% row_class = index%2 == 0 ? 'even' : 'odd' %>
- <% backlog_item = @sprint.backlog_items.find_by_user_story_id(story.id) %>
- <tr class="<%= row_class %>">
+ <% @user_stories.each do |story| %>
+ <tr class="<%= cycle('odd', 'even') %>">
<td><%= story.id %></td>
<td><%= story.priority %></td>
<td>
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
index c41382b..21c47c4 100644
--- a/config/initializers/mailer.rb
+++ b/config/initializers/mailer.rb
@@ -14,21 +14,26 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-MAIL_CONFIG = YAML.load(File.open("#{RAILS_ROOT}/config/mailer.yml"))
-
require 'tlsmail'
-Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
-ActionMailer::Base.delivery_method = MAIL_CONFIG[:delivery_method]
-ActionMailer::Base.perform_deliveries = MAIL_CONFIG[:perform_deliveries]
-ActionMailer::Base.default_charset = MAIL_CONFIG[:default_charset]
-ActionMailer::Base.raise_delivery_errors = MAIL_CONFIG[:raise_delivery_errors]
+def load_email_config
+ puts "Reloading email configuration"
+ Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
+ ActionMailer::Base.delivery_method = ConfigProperty.value_by_name('email.server.type')
+ ActionMailer::Base.perform_deliveries = ConfigProperty.value_by_name('email.server.perform_deliveries')
+ ActionMailer::Base.default_charset = 'utf-8'
+ ActionMailer::Base.raise_delivery_errors = true
+
+ ActionMailer::Base.smtp_settings = {
+ :address => ConfigProperty.value_by_name('email.server.name'),
+ :port => ConfigProperty.value_by_name('email.server.port'),
+ :tls => ConfigProperty.value_by_name('email.server.smtp_tls'),
+ :authentication => ConfigProperty.value_by_name('email.server.auth_mode'),
+ :user_name => ConfigProperty.value_by_name('email.server.username'),
+ :password => ConfigProperty.value_by_name('email.server.password')
+ }
+
+ puts ActionMailer::Base.smtp_settings
+end
-ActionMailer::Base.smtp_settings = {
- :address => MAIL_CONFIG[:server_name],
- :port => MAIL_CONFIG[:server_port],
- :tls => MAIL_CONFIG[:require_smtp_tls],
- :authentication => MAIL_CONFIG[:server_auth_mode],
- :user_name => MAIL_CONFIG[:server_username],
- :password => MAIL_CONFIG[:server_password]
-}
+load_email_config
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
deleted file mode 100644
index 1dd4aa2..0000000
--- a/config/mailer.yml.example
+++ /dev/null
@@ -1,12 +0,0 @@
----
-:delivery_method: :smtp
-:require_smtp_tls: true
-:perform_deliveries: true
-:default_charset: utf-8
-:raise_delivery_errors: true
-:server_name: smtp.gmail.com
-:server_port: 587
-:server_auth_mode: :login
-:server_username: your_username
-:server_password: your_password
-:from: noreply(a)projxp.org
diff --git a/config/routes.rb b/config/routes.rb
index 2be7330..83818ca 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -16,6 +16,9 @@
#
ActionController::Routing::Routes.draw do |map|
+ map.resource :admin, :plural => :admin do |admin|
+ admin.resource :email, :plural => :email
+ end
map.resources :projects
map.resources :products do |product|
product.resources :roles
diff --git a/db/migrate/023_add_admin_site_to_user_privileges.rb b/db/migrate/023_add_admin_site_to_user_privileges.rb
new file mode 100644
index 0000000..565f414
--- /dev/null
+++ b/db/migrate/023_add_admin_site_to_user_privileges.rb
@@ -0,0 +1,33 @@
+# 023_add_admin_site_to_user_privileges.rb
+# Copyright (C) 2008, 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 AddAdminSiteToUserPrivileges < ActiveRecord::Migration
+ def self.up
+ add_column :user_privileges, :admin_site, :boolean, :default => false
+
+ # make the admin account a site admin
+ privileges = UserPrivilege.find_by_user_id(1)
+ if privileges
+ privileges.admin_site = true
+ privileges.save!
+ end
+ end
+
+ def self.down
+ remove_column :user_privileges, :admin_site
+ end
+end
diff --git a/db/migrate/024_create_config_properties.rb b/db/migrate/024_create_config_properties.rb
new file mode 100644
index 0000000..5bcb87b
--- /dev/null
+++ b/db/migrate/024_create_config_properties.rb
@@ -0,0 +1,31 @@
+# 024_create_config_properties.rb
+# Copyright (C) 2008, 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 CreateConfigProperties < ActiveRecord::Migration
+ def self.up
+ create_table :config_properties do |t|
+ t.string :name, :null => false, :limit => 128
+ t.text :value, :null => true
+
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :config_properties
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 90c8c4a..a1b0dce 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 22) do
+ActiveRecord::Schema.define(:version => 24) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -25,6 +25,13 @@ ActiveRecord::Schema.define(:version => 22) do
add_index "backlog_items", ["sprint_id", "user_story_id"], :name => "index_backlog_items_on_sprint_id_and_user_story_id", :unique => true
add_index "backlog_items", ["user_story_id"], :name => "fk_backlog_items_user_story"
+ create_table "config_properties", :force => true do |t|
+ t.string "name", :limit => 128, :null => false
+ t.text "value"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
create_table "notifications", :force => true do |t|
t.integer "user_id"
t.boolean "task_reminders"
@@ -139,6 +146,7 @@ ActiveRecord::Schema.define(:version => 22) do
t.boolean "admin_users", :default => false, :null => false
t.datetime "created_at"
t.datetime "updated_at"
+ t.boolean "admin_site", :default => false
end
add_index "user_privileges", ["user_id"], :name => "fk_privilege_user"
diff --git a/public/stylesheets/forms.css b/public/stylesheets/forms.css
index 07dc248..51bcc2e 100644
--- a/public/stylesheets/forms.css
+++ b/public/stylesheets/forms.css
@@ -23,11 +23,9 @@ table.edit {
}
table.edit col.label {
- width: 15em;
}
table.edit col.value {
- width: 100%;
}
table.edit {
diff --git a/test/fixtures/config_properties.yml b/test/fixtures/config_properties.yml
new file mode 100644
index 0000000..b83d3d6
--- /dev/null
+++ b/test/fixtures/config_properties.yml
@@ -0,0 +1,3 @@
+mail_server_name:
+ name: email.server.name
+ value: smtp.gmail.com
diff --git a/test/fixtures/user_privileges.yml b/test/fixtures/user_privileges.yml
index 38ffbf7..ba57357 100644
--- a/test/fixtures/user_privileges.yml
+++ b/test/fixtures/user_privileges.yml
@@ -4,6 +4,7 @@ admin_privileges:
user_id: <%= Fixtures.identify(:admin) %>
admin_projects: true
admin_users: true
+ admin_site: true
projxp_owner_privileges:
user_id: <%= Fixtures.identify(:projxp_owner) %>
diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb
new file mode 100644
index 0000000..d4c1dd4
--- /dev/null
+++ b/test/functional/admin_controller_test.rb
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class AdminControllerTest < ActionController::TestCase
+ # Replace this with your real tests.
+ def test_truth
+ assert true
+ end
+end
diff --git a/test/functional/emails_controller_test.rb b/test/functional/emails_controller_test.rb
new file mode 100644
index 0000000..86f4bca
--- /dev/null
+++ b/test/functional/emails_controller_test.rb
@@ -0,0 +1,108 @@
+# email_controller_test.rb
+# Copyright (C) 2008, 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/>.
+#
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class EmailsControllerTest < ActionController::TestCase
+ fixtures :users
+
+ def setup
+ @admin = users(:admin)
+ raise "Admin must have site admin rights." unless @admin.privileges.admin_site
+ @nonadmin = users(:mcpierce)
+ raise "Nonadmin cannot have site admin rights." if @nonadmin.privileges.admin_site
+ end
+
+ # Ensures that anonymous users cannot view the email configuration.
+ def test_show_as_anonymous
+ get :show
+
+ assert_redirected_to login_path
+ end
+
+ # Ensures that users who are not site admins cannot view the configuration.
+ def test_show_as_nonadmin
+ get :show, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that administrators can view the email configuration.
+ def test_show
+ get :show, {}, {:user_id => @admin.id}
+
+ assert_response :success
+ assert assigns['properties']
+ properties = assigns['properties']
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ assert properties["#{property}"], "Missing property: #{property}"
+ end
+ end
+
+ # Ensures that an anonymous user cannot access the edit email page.
+ def test_edit_as_anonymous
+ get :edit
+
+ assert_redirected_to login_url
+ end
+
+ # Ensures that a non-admin cannot access the edit page.
+ def test_edit_as_nonadmin
+ get :edit, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that an admin can edit the email settings.
+ def test_edit
+ get :edit, {}, {:user_id => @admin.id}
+
+ assert_response :success
+ end
+
+ # Ensures that an anonymous user cannot update the mail settings.
+ def test_update_as_anonymous
+ put :update
+
+ assert_redirected_to :login_url
+ end
+
+ # Ensures that a nonadmin cannot update the mail settings.
+ def test_update_as_nonadmin
+ put :update, {}, {:user_id => @nonadmin.id}
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that updating works as expected.
+ def test_update
+ updates = Hash.new
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ updates[property] = property.reverse
+ end
+
+ put :update, {:properties => updates}, {:user_id => @admin.id}
+
+ assert_redirected_to admin_email_url
+ EmailsController::EMAIL_PROPERTIES.each do |property|
+ config_property = ConfigProperty.find_by_name(property)
+ assert config_property, "Property was not saved."
+ assert_equal updates[property], config_property.value,
+ "Value was not saved correctly."
+ end
+ end
+end
diff --git a/test/unit/config_property_test.rb b/test/unit/config_property_test.rb
new file mode 100644
index 0000000..98c305d
--- /dev/null
+++ b/test/unit/config_property_test.rb
@@ -0,0 +1,46 @@
+# config_property_test.rb
+# Copyright (C) 2008, 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/>.
+#
+
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ConfigPropertyTest < ActiveSupport::TestCase
+ def setup
+ @config_property = ConfigProperty.new(:name => 'name', :value => 'value')
+ @existing_property = config_properties(:mail_server_name)
+ end
+
+ # Ensures that a config property requires a name.
+ def test_name_required
+ @config_property.name = nil
+
+ fail "The name must be required." if @config_property.valid?
+ end
+
+ # Ensures that a config property name must be unique.
+ def test_name_unique
+ @config_property.name = @existing_property.name
+
+ fail "The name must be unique." if @config_property.valid?
+ end
+
+ # Ensures that a value does not need to be present.
+ def test_value_not_required
+ @config_property.value = nil
+
+ fail "The value is not required." unless @config_property.valid?
+ end
+end
--
1.6.0.2
15 years, 3 months
Master branch is now closed...
by Darryl L. Pierce
Going forward, please only do development on the devel branch and not
against master. Master is now going to be locked down and will
reflect the current latest release of ProjXP.
Please read the instructions here:
https://fedorahosted.org/projxp/wiki/Download
for details on how to move over to devel for ongoing work. If you have
any questions, shoot an email to the list. :)
--
Darryl L. Pierce <mcpierce(a)gmail.com>
Visit the Infobahn Offramp: <http://mcpierce.multiply.com>
"Bury me next to my wife. Nothing too fancy..." - Ulysses S. Grant
15 years, 3 months
[PATCH] When planning a sprint, closed user stories should not be displayed. #91
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/controllers/sprints_controller.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/app/controllers/sprints_controller.rb
b/app/controllers/sprints_controller.rb
index 693121a..f4e7557 100644
--- a/app/controllers/sprints_controller.rb
+++ b/app/controllers/sprints_controller.rb
@@ -153,7 +153,7 @@ class SprintsController < ApplicationController
if @sprint.pending?
if @sprint.can_populate?(@user)
@title = "Sprint #{(a)sprint.id} (Planning)"
- @user_stories = UserStory.find_all_by_product_id((a)product.id)
+ @user_stories =
UserStory.find_all_by_product_id_and_closed((a)product.id, false)
@selected = []
@estimates = {}
--
1.6.0.2
15 years, 3 months
[PATCH] User stories are closed when the sprint is completed if the related backlog item was completed. #81
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/sprint.rb | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/app/models/sprint.rb b/app/models/sprint.rb
index 1fffb5b..bd7c788 100644
--- a/app/models/sprint.rb
+++ b/app/models/sprint.rb
@@ -56,6 +56,8 @@ class Sprint < ActiveRecord::Base
validates_presence_of :goals,
:message => 'Please list the goals for this sprint.'
+ after_update :close_user_stories
+
belongs_to :product
has_many :backlog_items, :dependent => :destroy
@@ -188,4 +190,20 @@ class Sprint < ActiveRecord::Base
return false
end
+
+ private
+
+ # When the user close a sprint, every user stories are close if the
related
+ # backlog item are completed.
+ def close_user_stories
+ return unless status == STATUS_CLOSED
+
+ self.backlog_items.each do |backlog_item|
+ if backlog_item.state == BacklogItem::STATE_COMPLETED
+ user_story = backlog_item.user_story
+ user_story.closed = true
+ user_story.save!
+ end
+ end
+ end
end
--
1.6.0.2
15 years, 3 months
[PATCH] An empty task list for backlog items should say "No tasks were found". #80
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/controllers/items_controller.rb | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/app/controllers/items_controller.rb
b/app/controllers/items_controller.rb
index fa68ad0..82a12a8 100644
--- a/app/controllers/items_controller.rb
+++ b/app/controllers/items_controller.rb
@@ -38,9 +38,14 @@ class ItemsController < ApplicationController
# GET /products/1/sprints/1/items/1
def show
- @title = "Backlog Item (#{(a)backlog_item.user_story.title})"
- respond_to do |format|
- format.html
+ if @tasks.empty?
+ flash[:message] = "No tasks were found for
#{(a)backlog_item.user_story.title}"
+ redirect_to product_sprint_path(@product, @sprint)
+ else
+ @title = "Backlog Item (#{(a)backlog_item.user_story.title})"
+ respond_to do |format|
+ format.html
+ end
end
end
--
1.6.0.2
15 years, 3 months
Installation instructions
by Darryl L. Pierce
I've written up preliminary installation instructions here:
https://fedorahosted.org/projxp/wiki/Installation
Please take a moment to review them and give me your feedback. I'm
planning to start working on the Fedora package for ProjXP once the
two outstanding bugs are fixed and the code pushed.
--
Darryl L. Pierce <mcpierce(a)gmail.com>
Visit the Infobahn Offramp: <http://mcpierce.multiply.com>
"Bury me next to my wife. Nothing too fancy..." - Ulysses S. Grant
15 years, 3 months
About #71
by LAN-SUN-LUK Benjamin
I see that I have nothing to do for this bug #71, because you have
already fix this bug with your last commit.
So, can I close the ticket #71?
---
Benjamin LAN-SUN-LUK
15 years, 3 months