[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by LAN-SUN-LUK Benjamin
This patch supercedes the last one.
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
If you want to use sendmail for the server. You have just to set "ActionMailer::Base.delivery_method = :sendmail" in "config/initializers/mailer.rb".
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 12 +---
config/initializers/mailer.rb | 20 +++++++
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 9 +++
test/unit/user_mailer_test.rb | 21 +++++++-
9 files changed, 137 insertions(+), 19 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/mailer.rb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..e6685d5 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -79,12 +82,3 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:date_time12 => "%m/%d/%Y %I:%M%p",
:date_time24 => "%m/%d/%Y %H:%M"
)
-
-# Mail configuration.
-# Please complete the config file are locate at /config/mailer.yml
-#
-require "smtp_tls"
-
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
new file mode 100644
index 0000000..f47c5cb
--- /dev/null
+++ b/config/initializers/mailer.rb
@@ -0,0 +1,20 @@
+# Mail configuration.
+# Please complete the config file that are locate at /config/mailer.yml
+#
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
+
+# Defines a delivery method. Possible values are :smtp (default), :sendmail,
+# and :test.
+ActionMailer::Base.delivery_method = :smtp
+
+if File.exist?(mailer_file_path)
+
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ require "smtp_tls" if MAIL_CONFIG[:require_smtp_tls]
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..fb58101
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..d6a6f18
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,9 @@
+---
+ :require_smtp_tls: false
+ :account:
+ :address: smtp.localhost.localdomain
+ :port: 25
+ :user_name: username
+ :password: password
+ :authentication: :login
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by Benjamin LAN-SUN-LUK
From: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
This patch supercedes the last one.
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
If you want to use sendmail for the server. You have just to set "ActionMailer::Base.delivery_method = :sendmail" in "config/initializers/mailer.rb".
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 12 +---
config/initializers/mailer.rb | 20 +++++++
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 9 +++
test/unit/user_mailer_test.rb | 21 +++++++-
9 files changed, 137 insertions(+), 19 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/mailer.rb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..e6685d5 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -79,12 +82,3 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:date_time12 => "%m/%d/%Y %I:%M%p",
:date_time24 => "%m/%d/%Y %H:%M"
)
-
-# Mail configuration.
-# Please complete the config file are locate at /config/mailer.yml
-#
-require "smtp_tls"
-
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
new file mode 100644
index 0000000..f47c5cb
--- /dev/null
+++ b/config/initializers/mailer.rb
@@ -0,0 +1,20 @@
+# Mail configuration.
+# Please complete the config file that are locate at /config/mailer.yml
+#
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
+
+# Defines a delivery method. Possible values are :smtp (default), :sendmail,
+# and :test.
+ActionMailer::Base.delivery_method = :smtp
+
+if File.exist?(mailer_file_path)
+
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ require "smtp_tls" if MAIL_CONFIG[:require_smtp_tls]
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..fb58101
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..d6a6f18
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,9 @@
+---
+ :require_smtp_tls: false
+ :account:
+ :address: smtp.localhost.localdomain
+ :port: 25
+ :user_name: username
+ :password: password
+ :authentication: :login
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by Benjamin LAN-SUN-LUK
From: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
This patch supercedes the last one.
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
If you want to use sendmail for the server. You have just to set "ActionMailer::Base.delivery_method = :sendmail" in "config/initializers/mailer.rb".
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 12 +---
config/initializers/mailer.rb | 20 +++++++
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 9 +++
test/unit/user_mailer_test.rb | 21 +++++++-
9 files changed, 137 insertions(+), 19 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/mailer.rb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..e6685d5 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -79,12 +82,3 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:date_time12 => "%m/%d/%Y %I:%M%p",
:date_time24 => "%m/%d/%Y %H:%M"
)
-
-# Mail configuration.
-# Please complete the config file are locate at /config/mailer.yml
-#
-require "smtp_tls"
-
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
new file mode 100644
index 0000000..f47c5cb
--- /dev/null
+++ b/config/initializers/mailer.rb
@@ -0,0 +1,20 @@
+# Mail configuration.
+# Please complete the config file that are locate at /config/mailer.yml
+#
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
+
+# Defines a delivery method. Possible values are :smtp (default), :sendmail,
+# and :test.
+ActionMailer::Base.delivery_method = :smtp
+
+if File.exist?(mailer_file_path)
+
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ require "smtp_tls" if MAIL_CONFIG[:require_smtp_tls]
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..fb58101
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..d6a6f18
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,9 @@
+---
+ :require_smtp_tls: false
+ :account:
+ :address: smtp.localhost.localdomain
+ :port: 25
+ :user_name: username
+ :password: password
+ :authentication: :login
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by Benjamin LAN-SUN-LUK
From: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
Thank you for your test ;-)
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
If you want to use sendmail for the server. You have just to set "ActionMailer::Base.delivery_method = :sendmail" in "config/initializers/mailer.rb".
Little change in mailer.yml.example, authentication is now login. Try to send mail.
Signed-off-by: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 12 +---
config/initializers/mailer.rb | 20 +++++++
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 9 +++
test/unit/user_mailer_test.rb | 21 +++++++-
9 files changed, 137 insertions(+), 19 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/mailer.rb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..e6685d5 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -79,12 +82,3 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:date_time12 => "%m/%d/%Y %I:%M%p",
:date_time24 => "%m/%d/%Y %H:%M"
)
-
-# Mail configuration.
-# Please complete the config file are locate at /config/mailer.yml
-#
-require "smtp_tls"
-
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
new file mode 100644
index 0000000..f47c5cb
--- /dev/null
+++ b/config/initializers/mailer.rb
@@ -0,0 +1,20 @@
+# Mail configuration.
+# Please complete the config file that are locate at /config/mailer.yml
+#
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
+
+# Defines a delivery method. Possible values are :smtp (default), :sendmail,
+# and :test.
+ActionMailer::Base.delivery_method = :smtp
+
+if File.exist?(mailer_file_path)
+
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ require "smtp_tls" if MAIL_CONFIG[:require_smtp_tls]
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..23113be
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item_owner
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..a42c3b1
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,9 @@
+---
+ :require_smtp_tls: false
+ :account:
+ :address: smtp.localhost.localdomain
+ :port: 25
+ :user_name: username
+ :password: password
+ :authentication: :plain
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by Benjamin LAN-SUN-LUK
From: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
I have done some change in mail management. Now, mail are managed at "config/initializers/mailer.rb".
For test mail, don't forget to complete the config file with your server adress, username, and password. If send mail not work, then feedback to me.
If you want to use sendmail for the server. You have just to set "ActionMailer::Base.delivery_method = :sendmail" in "config/initializers/mailer.rb".
I will write a wiki if mail were functional.
Signed-off-by: Benjamin LAN-SUN-LUK <benji(a)Wloups.lan>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 12 +---
config/initializers/mailer.rb | 20 +++++++
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 13 +++--
config/mailer.yml.example | 9 +++
test/unit/user_mailer_test.rb | 21 +++++++-
9 files changed, 145 insertions(+), 18 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/mailer.rb
create mode 100644 config/initializers/schedules.rb
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..e6685d5 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -79,12 +82,3 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
:date_time12 => "%m/%d/%Y %I:%M%p",
:date_time24 => "%m/%d/%Y %H:%M"
)
-
-# Mail configuration.
-# Please complete the config file are locate at /config/mailer.yml
-#
-require "smtp_tls"
-
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
new file mode 100644
index 0000000..f47c5cb
--- /dev/null
+++ b/config/initializers/mailer.rb
@@ -0,0 +1,20 @@
+# Mail configuration.
+# Please complete the config file that are locate at /config/mailer.yml
+#
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
+
+# Defines a delivery method. Possible values are :smtp (default), :sendmail,
+# and :test.
+ActionMailer::Base.delivery_method = :smtp
+
+if File.exist?(mailer_file_path)
+
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ require "smtp_tls" if MAIL_CONFIG[:require_smtp_tls]
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..23113be
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item_owner
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
index f62d51e..9488ef1 100644
--- a/config/mailer.yml
+++ b/config/mailer.yml
@@ -1,6 +1,9 @@
---
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
+ :require_smtp_tls: false
+ :account:
+ :address: mail.izi.re
+ :port: 25
+ :user_name: maximin.lansunluk
+ :password: dbe5360d
+ :authentication: :login
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..a42c3b1
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,9 @@
+---
+ :require_smtp_tls: false
+ :account:
+ :address: smtp.localhost.localdomain
+ :port: 25
+ :user_name: username
+ :password: password
+ :authentication: :plain
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by LAN-SUN-LUK Benjamin
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at
"config/mailer.yml.example"
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 14 ++++-
config/initializers/schedules.rb | 54
++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 8 +++
test/unit/user_mailer_test.rb | 21 +++++++-
8 files changed, 124 insertions(+), 13 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been
detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb
b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against
them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb
b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a
moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..ed31242 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -84,7 +87,12 @@
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
# Please complete the config file are locate at /config/mailer.yml
#
require "smtp_tls"
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
+if File.exist?(mailer_file_path)
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb
b/config/initializers/schedules.rb
new file mode 100644
index 0000000..65d4984
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do
|backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] <<
backlog_item_owner
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] <<
backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..66644a9
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,8 @@
+---
+ :account:
+ :address: smtp.gmail.com
+ :port: 587
+ :user_name: username(a)gmail.com
+ :password: password
+ :authentication: :plain
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by Benjamin LAN-SUN-LUK
From: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
Required:
- Install gems, use: "rake gems:install"
- Configure mail, create a file at "config/mailer.yml". Use example at "config/mailer.yml.example"
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 22 ++++++++-
.../user_mailer/no_activity_recorded.html.erb | 6 ++
app/views/user_mailer/no_task_recorded.html.erb | 6 ++
config/environment.rb | 14 ++++-
config/initializers/schedules.rb | 54 ++++++++++++++++++++
config/mailer.yml | 6 --
config/mailer.yml.example | 8 +++
test/unit/user_mailer_test.rb | 21 +++++++-
8 files changed, 124 insertions(+), 13 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 app/views/user_mailer/no_task_recorded.html.erb
create mode 100644 config/initializers/schedules.rb
delete mode 100644 config/mailer.yml
create mode 100644 config/mailer.yml.example
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..bd42800 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -3,8 +3,28 @@ class UserMailer < ActionMailer::Base
#
def new_generated_password(user, new_password)
recipients user.email
- from "no_reply(a)projxp.org" # TODO Email must be edit
+ from MAIL_CONFIG[:from]
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an email to a user to notify him that no activity has been detected
+ # in his backlog.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
+
+ # Send an email to a user to notify him that no task has been detected
+ # in his backlog.
+ #
+ def no_task_recorded(user, backlog_items)
+ recipients user.email
+ from MAIL_CONFIG[:from]
+ subject "No task has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..8f7a005
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but no tasks were entered against them. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/app/views/user_mailer/no_task_recorded.html.erb b/app/views/user_mailer/no_task_recorded.html.erb
new file mode 100644
index 0000000..a912ec1
--- /dev/null
+++ b/app/views/user_mailer/no_task_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+The following backlog items are active, but tasks are empty. Please take a moment to update them.
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..ed31242 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -84,7 +87,12 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
# Please complete the config file are locate at /config/mailer.yml
#
require "smtp_tls"
+mailer_file_path = "#{RAILS_ROOT}/config/mailer.yml"
-mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
-mailer_options = YAML.load(mailer_config)
-ActionMailer::Base.smtp_settings = mailer_options
+if File.exist?(mailer_file_path)
+ MAIL_CONFIG = YAML.load(File.open(mailer_file_path))
+ ActionMailer::Base.smtp_settings = MAIL_CONFIG[:account]
+else
+ raise "Mail configuration file not found at #{mailer_file_path}"
+end
+MAIL_CONFIG ||= {}
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..65d4984
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,54 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 05:00 am
+ scheduler.schedule('0 5 * * *') do # TODO Time must be configurable
+
+ user_no_activity_on_backlog_items = {}
+ user_no_tasks_on_backlog_items = {}
+
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ if backlog_item.tasks.empty?
+
+ backlog_item_owner = backlog_item.owner
+ user_no_tasks_on_backlog_items[backlog_item_owner] ||= []
+ user_no_tasks_on_backlog_items[backlog_item_owner] << backlog_item_owner
+
+ else
+
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+
+ end
+ end
+
+ # Send the e-mail
+
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ user_no_tasks_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_task_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
diff --git a/config/mailer.yml b/config/mailer.yml
deleted file mode 100644
index f62d51e..0000000
--- a/config/mailer.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
- :address: smtp.gmail.com
- :port: 587
- :user_name: username(a)gmail.com
- :password: password
- :authentication: :plain
diff --git a/config/mailer.yml.example b/config/mailer.yml.example
new file mode 100644
index 0000000..66644a9
--- /dev/null
+++ b/config/mailer.yml.example
@@ -0,0 +1,8 @@
+---
+ :account:
+ :address: smtp.gmail.com
+ :port: 587
+ :user_name: username(a)gmail.com
+ :password: password
+ :authentication: :plain
+ :from: no-reply(a)projxp.org
\ No newline at end of file
diff --git a/test/unit/user_mailer_test.rb b/test/unit/user_mailer_test.rb
index d68a249..7d5fc15 100644
--- a/test/unit/user_mailer_test.rb
+++ b/test/unit/user_mailer_test.rb
@@ -2,8 +2,23 @@ require 'test_helper'
class UserMailerTest < ActionMailer::TestCase
tests UserMailer
- # TODO Test user_mailer
- def test_truth
- assert true
+
+ def setup
+ @user = User.new(:email => 'test(a)projxp.org', :display_name => 'Test')
+ backlog_item = BacklogItem.new
+ backlog_item.user_story = UserStory.new(:title => 'Test')
+ @backlog_items = [backlog_item]
+ end
+
+ def test_new_generated_password
+ assert UserMailer.deliver_new_generated_password(@user, 'password')
+ end
+
+ def test_no_activity_recorded
+ assert UserMailer.deliver_no_activity_recorded(@user, @backlog_items)
+ end
+
+ def test_no_task_recorded
+ assert UserMailer.deliver_no_task_recorded(@user, @backlog_items)
end
end
--
1.5.2.4
15 years, 6 months
[PROJXP [PATCH] Users can view a burndown chart for a sprint. #7
by Darryl L. Pierce
(EDIT: This supercedes the previous and only has a fixed commit message)
Added a mapping for burndown charts. URLs will be in the format:
/report/burndown/[id]
where id is the sprint's id.
The day argument is an optional parameter. If it is not included
then the current status of the sprint is reported.
This patch requires you to run a migration, and the gruff gem to be
installed.
---
app/controllers/backlog_controller.rb | 7 ++-
app/controllers/report_controller.rb | 56 ++++++++++++++++++++++
app/controllers/task_controller.rb | 1 -
app/controllers/user_story_controller.rb | 1 -
app/helpers/report_helper.rb | 2 +
app/models/backlog_item.rb | 18 ++++++-
app/models/sprint.rb | 22 +++++++++
app/views/report/burndown.html.erb | 3 +
app/views/sprint/view.html.erb | 33 +++++++------
config/environment.rb | 52 +++-----------------
config/routes.rb | 1 -
db/migrate/015_add_explicit_date_to_estimates.rb | 16 ++++++
db/schema.rb | 3 +-
test/fixtures/remaining_hours_estimates.yml | 2 +
test/functional/backlog_controller_test.rb | 15 +++++-
test/functional/report_controller_test.rb | 52 ++++++++++++++++++++
test/unit/backlog_item_test.rb | 2 +-
test/unit/sprint_test.rb | 4 +-
18 files changed, 217 insertions(+), 73 deletions(-)
create mode 100644 app/controllers/report_controller.rb
create mode 100644 app/helpers/report_helper.rb
create mode 100644 app/views/report/burndown.html.erb
create mode 100644 db/migrate/015_add_explicit_date_to_estimates.rb
create mode 100644 test/functional/report_controller_test.rb
diff --git a/app/controllers/backlog_controller.rb b/app/controllers/backlog_controller.rb
index 9e3ea1d..e033149 100644
--- a/app/controllers/backlog_controller.rb
+++ b/app/controllers/backlog_controller.rb
@@ -67,7 +67,8 @@ class BacklogController < ApplicationController
@backlog_item.remaining_hours_estimates << RemainingHoursEstimate.create(
:backlog_item_id => @backlog_item.id,
:user_id => @user.id,
- :hours => params[:hours])
+ :hours => params[:hours],
+ :estimated_on => Date.today)
end
rescue Exception => error
@@ -147,6 +148,7 @@ class BacklogController < ApplicationController
begin
BacklogItem.transaction do
@backlog_item.state = BacklogItem::STATE_COMPLETED
+ @backlog_item.update_remaining_hours(0.0, @user)
@backlog_item.save
end
@@ -170,6 +172,7 @@ class BacklogController < ApplicationController
BacklogItem.transaction do
@backlog_item.state = BacklogItem::STATE_CANCELED
@backlog_item.owner = nil
+ @backlog_item.update_remaining_hours(0.0, @user)
@backlog_item.save!
end
@@ -188,7 +191,7 @@ class BacklogController < ApplicationController
def reopen
if @backlog_item.user_can_reopen?(@user)
BacklogItem.transaction do
- @backlog_item.state = @backlog_item.owner ? BacklogItem::STATE_ASSIGNED : BacklogItem::PENDING
+ @backlog_item.state = @backlog_item.owner ? BacklogItem::STATE_ASSIGNED : BacklogItem::STATE_PENDING
@backlog_item.save!
redirect_to :action => :view, :id => @backlog_item.id
diff --git a/app/controllers/report_controller.rb b/app/controllers/report_controller.rb
new file mode 100644
index 0000000..c3ca4a1
--- /dev/null
+++ b/app/controllers/report_controller.rb
@@ -0,0 +1,56 @@
+# report_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/>.
+#
+
+# +ReportController+ allows users to view various reports.
+#
+class ReportController < ApplicationController
+ before_filter :load_sprint
+
+ # Generates a burndown report.
+ #
+ def burndown_graphic
+ if @sprint.can_view_burndown?
+ @data = @sprint.burndown_data
+
+ g = Gruff::Line.new('800x600')
+ g.title = "Burndown Chart For '#{(a)sprint.title}'"
+
+ g.font = File.expand_path('Courier.ttf', RAILS_ROOT)
+ g.data("Remaining hours", @data)
+ g.labels= {
+ 0 => @sprint.start.to_s(:date),
+ (@sprint.duration / 2) => (@sprint.start + (@sprint.duration / 2)).to_s(:date),
+ (@sprint.duration - 1) => (@sprint.start + (@sprint.duration - 1)).to_s(:date)}
+
+ send_data(g.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "site-stats.png")
+ else
+ flash[:error] = 'Cannot view a burndown chart for this sprint.'
+ redirect_to :controller => :sprint, :action => :view, :id => @sprint.id
+ end
+ end
+
+ private
+
+ def load_sprint
+ @sprint = Sprint.find_by_id(params[:id])
+
+ unless @sprint
+ flash[:error] = 'Missing or invalid sprint id.'
+ redirect_to error_url
+ end
+ end
+end
diff --git a/app/controllers/task_controller.rb b/app/controllers/task_controller.rb
index 0692e6f..6c6e42b 100644
--- a/app/controllers/task_controller.rb
+++ b/app/controllers/task_controller.rb
@@ -42,7 +42,6 @@ class TaskController < ApplicationController
rescue ActiveRecord::RecordInvalid => error
flash[:message] = error.message
- puts ":::#{error.message}"
@task.valid?
render :action => :create
end
diff --git a/app/controllers/user_story_controller.rb b/app/controllers/user_story_controller.rb
index 9f5633d..83e567c 100644
--- a/app/controllers/user_story_controller.rb
+++ b/app/controllers/user_story_controller.rb
@@ -69,7 +69,6 @@ class UserStoryController < ApplicationController
end
rescue ActiveRecord::RecordInvalid => error
- puts ":::ERROR:#{error.message}"
@user_story.valid?
render :modify
end
diff --git a/app/helpers/report_helper.rb b/app/helpers/report_helper.rb
new file mode 100644
index 0000000..0847d3b
--- /dev/null
+++ b/app/helpers/report_helper.rb
@@ -0,0 +1,2 @@
+module ReportHelper
+end
diff --git a/app/models/backlog_item.rb b/app/models/backlog_item.rb
index 0eea0b3..55024c4 100644
--- a/app/models/backlog_item.rb
+++ b/app/models/backlog_item.rb
@@ -66,8 +66,22 @@ class BacklogItem < ActiveRecord::Base
remaining_hours_estimates.last.hours
end
- def remaining_hours=(hours)
- remaining_hours_estimates << RemainingHoursEstimate.new(:hours => hours)
+ def remaining_hours_for_date(date)
+ result = estimated_hours
+
+ remaining_hours_estimates.each do |estimate|
+ result = estimate.hours.to_f if estimate.estimated_on <= date
+ end
+
+ return result
+ end
+
+ def update_remaining_hours(hours, user)
+ remaining_hours_estimates <<
+ RemainingHoursEstimate.new(
+ :hours => hours,
+ :user_id => user.id,
+ :estimated_on => Date.today)
end
# Returns whether the given user can modify this backlog item.
diff --git a/app/models/sprint.rb b/app/models/sprint.rb
index 157396c..bf4a4ee 100644
--- a/app/models/sprint.rb
+++ b/app/models/sprint.rb
@@ -100,6 +100,12 @@ class Sprint < ActiveRecord::Base
backlog_items.inject(0) { |sum, item| sum + item.remaining_hours}
end
+ # Returns the number of hours remaining for the specified day.
+ #
+ def remaining_hours_for_day(day)
+ backlog_items.inject(0) { |sum, item| sum + item.remaining_hours_for_date(start + day) }
+ end
+
# Returns whether the specified user can modify this sprint.
#
def user_can_modify(user)
@@ -118,6 +124,22 @@ class Sprint < ActiveRecord::Base
status == STATUS_ACTIVE
end
+ # Returns whether a burndown chart can be viewed for this sprint.
+ #
+ def can_view_burndown?
+ status != STATUS_PLANNED
+ end
+
+ # Returns the data as of the given day into the sprint.
+ #
+ def burndown_data
+ data = []
+
+ (0..duration).each { |day| data[day] = remaining_hours_for_day(day) }
+
+ return data
+ end
+
# Returns whether the sprint is in a healthy state or not.
#
def healthy?
diff --git a/app/views/report/burndown.html.erb b/app/views/report/burndown.html.erb
new file mode 100644
index 0000000..b5fa23f
--- /dev/null
+++ b/app/views/report/burndown.html.erb
@@ -0,0 +1,3 @@
+<img src="<%= url_for :action => :burndown_graphic, :id => @sprint.id %>"
+ alt="Burndown"
+ align="center" />
\ No newline at end of file
diff --git a/app/views/sprint/view.html.erb b/app/views/sprint/view.html.erb
index cfa0a58..c6a1659 100644
--- a/app/views/sprint/view.html.erb
+++ b/app/views/sprint/view.html.erb
@@ -1,10 +1,13 @@
<div style="width: 100%; overflow: auto">
<div style="float: left; width: 33%;">
<div class="toolbar">
-
+
<%= link_to "Edit", :action => :modify, :id => @sprint %>
<%= link_to "Populate", :action => :populate, :id => @sprint %>
-
+ <% if @sprint.can_view_burndown? %>
+ <%= link_to "Burndown", :controller => :report, :action => :burndown, :id => @sprint.id %>
+ <% end %>
+
</div>
<table class="details">
<thead>
@@ -12,14 +15,14 @@
<th class="title" colspan="2"><%= @sprint.title %></th>
</tr>
</thead>
-
+
<tbody>
<tr>
<td class="label">Status:</td>
- <td class="value">
+ <td class="value">
<% if @sprint.user_can_modify(@user) %>
<% form_tag(:action => :status, :id => @sprint.id) do %>
- <%= select_tag "status",
+ <%= select_tag "status",
options_for_select(Sprint::STATUS_TEXT, @sprint.status) %>
<%= submit_tag "Apply" %>
<% end %>
@@ -28,36 +31,36 @@
<% end %>
</td>
</tr>
-
+
<tr>
<td class="label">Starts:</td>
<td class="value"><%= @sprint.start.to_s(:date) %></td>
</tr>
-
+
<tr>
<td class="label">Ends:</td>
<td class="value"><%= @sprint.end_date.to_s(:date) %>
</tr>
-
+
<tr>
<td class="label">Hours E/A/R:</td>
<td class="value"><%= "#{@sprint.estimated_hours}/#{@sprint.actual_hours}/#{(a)sprint.remaining_hours}" %></td>
</tr>
-
+
<tr>
<td class="text" colspan="2"><%= simple_format @sprint.goals %></td>
</tr>
</tbody>
-
+
</table>
</div>
-
+
<div style="width: 66%; float:left;">
-
+
<%= will_paginate @backlog_items %>
-
-
- <%= render :partial => 'backlog/list',
+
+
+ <%= render :partial => 'backlog/list',
:object => @backlog_items.sort {|item1, item2| item1.user_story.priority <=> item2.user_story.priority},
:locals => {:title => 'Sprint Backlog'}%>
</div>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..dec56ec 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -1,25 +1,25 @@
# environment.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/>.
-#
+#
# Be sure to restart your server when you modify this file
# Uncomment below to force Rails into production mode when you don't control
-# web/app server and can't set it the proper way ENV['RAILS_ENV'] ||=
-# 'production'
+# web/app server and can't set it the proper way
+# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
# #RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
@@ -28,50 +28,12 @@
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
- # Settings in config/environments/* take precedence over those specified here.
- # Application configuration should go into files in config/initializers -- all
- # .rb files in that directory are automatically loaded. See
- # Rails::Configuration for more options.
-
- # Skip frameworks you're not going to use (only works if using vendor/rails).
- # To use Rails without a database, you must remove the Active Record framework
- # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
-
- # Only load the plugins named here, in the order given. By default, all
- # plugins in vendor/plugins are loaded in alphabetical order. :all can be used
- # as a placeholder for all plugins not explicitly named config.plugins = [
- # :exception_notification, :ssl_requirement, :all ]
-
- # Add additional load paths for your own custom dirs config.load_paths += %W(
- # #{RAILS_ROOT}/extras )
-
- # Force all environments to use the same logger level (by default production
- # uses :info, the others :debug) config.log_level = :debug
-
- # Your secret key for verifying cookie session data integrity. If you change
- # this key, all old sessions will become invalid! Make sure the secret is at
- # least 30 characters and all random, no regular words or you'll be exposed to
- # dictionary attacks.
config.action_controller.session = {
:session_key => '_chiroxp_session',
:secret => 'bb5e22a8065951948272bccbeff6c1e1fa1eff29e85dabcefe7577b68795d9e42cfc9a18426f84aee6722bb4859bf8b144a98fa58891e6c1f215dc3b6f38d2b3'
}
- # Use the database for sessions instead of the cookie-based default, which
- # shouldn't be used to store highly confidential information (create the
- # session table with 'rake db:sessions:create')
- # config.action_controller.session_store = :active_record_store
-
- # Use SQL instead of Active Record's schema dumper when creating the test
- # database. This is necessary if your schema can't be completely dumped by the
- # schema dumper, like if you have constraints or database-specific column
- # types config.active_record.schema_format = :sql
-
- # Activate observers that should always be running
- # config.active_record.observers = :cacher, :garbage_collector
-
- # Make Active Record use UTC-base instead of local time
- # config.active_record.default_timezone = :utc
+ config.gem "gruff"
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
diff --git a/config/routes.rb b/config/routes.rb
index e1f81cc..1108059 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -23,7 +23,6 @@ ActionController::Routing::Routes.draw do |map|
# Error handling
map.error "/error", :controller => 'home', :action => 'error'
-
# Install the default routes as the lowest priority.
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
diff --git a/db/migrate/015_add_explicit_date_to_estimates.rb b/db/migrate/015_add_explicit_date_to_estimates.rb
new file mode 100644
index 0000000..f300931
--- /dev/null
+++ b/db/migrate/015_add_explicit_date_to_estimates.rb
@@ -0,0 +1,16 @@
+class AddExplicitDateToEstimates < ActiveRecord::Migration
+ def self.up
+ add_column :remaining_hours_estimates, :estimated_on, :datetime
+
+ RemainingHoursEstimate.find(:all).each do |estimate|
+ estimate.estimated_on = estimate.created_at
+ estimate.save!
+ end
+
+ change_column :remaining_hours_estimates, :estimated_on, :datetime, :null => false
+ end
+
+ def self.down
+ remove_column :remaining_hours_estimates, :estimated_on
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c773644..4a20449 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 => 14) do
+ActiveRecord::Schema.define(:version => 15) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -62,6 +62,7 @@ ActiveRecord::Schema.define(:version => 14) do
t.decimal "hours", :precision => 5, :scale => 2, :null => false
t.datetime "created_at"
t.datetime "updated_at"
+ t.datetime "estimated_on", :null => false
end
create_table "roles", :force => true do |t|
diff --git a/test/fixtures/remaining_hours_estimates.yml b/test/fixtures/remaining_hours_estimates.yml
index 6e2e09b..b5ecd13 100644
--- a/test/fixtures/remaining_hours_estimates.yml
+++ b/test/fixtures/remaining_hours_estimates.yml
@@ -2,8 +2,10 @@ owned_backlog_item_remaining_one:
backlog_item_id: <%= Fixtures.identify(:owned_backlog_item) %>
user_id: <%= Fixtures.identify(:mcpierce) %>
hours: 2.5
+ estimated_on: <%= Date.today.to_s(:db) %>
owned_backlog_item_remaining_two:
backlog_item_id: <%= Fixtures.identify(:owned_backlog_item) %>
user_id: <%= Fixtures.identify(:mcpierce) %>
hours: 4.5
+ estimated_on: <%= Date.today.next.to_s(:db) %>
diff --git a/test/functional/backlog_controller_test.rb b/test/functional/backlog_controller_test.rb
index 4657b2d..cb2b041 100644
--- a/test/functional/backlog_controller_test.rb
+++ b/test/functional/backlog_controller_test.rb
@@ -38,8 +38,10 @@ class BacklogControllerTest < ActionController::TestCase
@completed_backlog_item = backlog_items(:closed_backlog_item)
flunk "Closed item should have a closed state!" unless @completed_backlog_item.state == BacklogItem::STATE_COMPLETED
+
@open_backlog_item = @owned_backlog_item
flunk "Open item should have an open state!" unless @open_backlog_item.state == BacklogItem::STATE_ASSIGNED
+
@task = tasks(:created_login_controller)
@sprint = @owned_backlog_item.sprint
end
@@ -282,6 +284,7 @@ class BacklogControllerTest < ActionController::TestCase
# Ensures that remaining hours must be a non-zero value.
#
def test_remaining_with_nonnumeric_hours
+ old_hours = @owned_backlog_item.remaining_hours.to_f
post :remaining,
{
:id => @owned_backlog_item.id,
@@ -290,7 +293,9 @@ class BacklogControllerTest < ActionController::TestCase
{:user_id => @owned_backlog_item.owner_id}
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
- assert flash.has_key?(:message)
+ result = BacklogItem.find_by_id((a)owned_backlog_item.id)
+ assert_equal old_hours, result.remaining_hours.to_f,
+ "Remaining hours should not have changed."
end
# Ensures that a negative remaining hours estimate is rejected.
@@ -310,6 +315,8 @@ class BacklogControllerTest < ActionController::TestCase
# Ensures that a zero hours remaining estimate is rejected.
#
def test_remaining_with_zero_hours
+ old_hours = @owned_backlog_item.remaining_hours
+
post :remaining,
{
:id => @owned_backlog_item.id,
@@ -318,7 +325,9 @@ class BacklogControllerTest < ActionController::TestCase
{:user_id => @owned_backlog_item.owner_id}
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
- assert flash.has_key?(:message)
+ result = BacklogItem.find_by_id((a)owned_backlog_item.id)
+ assert_equal old_hours.to_f, result.remaining_hours.to_f,
+ 'Remaining hours should not have changed.'
end
# Ensures that someone who is not the backlog item owner can't update the
@@ -354,7 +363,7 @@ class BacklogControllerTest < ActionController::TestCase
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
result = BacklogItem.find_by_id((a)owned_backlog_item.id)
- assert_equal 2.5, result.remaining_hours, 'Remaining hours not updated correctly.'
+ assert_equal 2.5, result.remaining_hours.to_f, 'Remaining hours not updated correctly.'
end
# Ensures that anonymous users cannot reopen a closed task.
diff --git a/test/functional/report_controller_test.rb b/test/functional/report_controller_test.rb
new file mode 100644
index 0000000..6957fe5
--- /dev/null
+++ b/test/functional/report_controller_test.rb
@@ -0,0 +1,52 @@
+# report_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 ReportControllerTest < ActionController::TestCase
+ fixtures :sprints
+
+ def setup
+ @pending_sprint = sprints(:inactive_sprint)
+ @sprint = sprints(:initial_development_sprint)
+ end
+
+ # Ensures that an error occurs when no sprint id was provided.
+ #
+ def test_burndown_graphic_without_sprint_id
+ get :burndown_graphics
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that trying to print a burndown report for a pending sprint fails.
+ #
+ def test_burndown_graphic_fails_for_pending_sprint
+ get :burndown_graphic, {:id => @pending_sprint.id}
+
+ assert_redirected_to :controller => :sprint, :action => :view, :id => @pending_sprint.id
+ end
+
+ # Ensures that a burndown chart works as expected.
+ #
+ def test_burndown_graphic
+ get :burndown_graphic, {:id => @sprint.id}
+
+ assert_response :success
+ assert assigns['data'], "Didn't generate the data needed for a report."
+ end
+end
diff --git a/test/unit/backlog_item_test.rb b/test/unit/backlog_item_test.rb
index fd24efa..c3cbc1b 100644
--- a/test/unit/backlog_item_test.rb
+++ b/test/unit/backlog_item_test.rb
@@ -67,7 +67,7 @@ class BacklogItemTest < ActiveSupport::TestCase
#
def test_remaining_hours_when_updated
@item.estimated_hours = 5.0
- @item.remaining_hours_estimates << RemainingHoursEstimate.new(:hours => 2.5)
+ @item.remaining_hours_estimates << RemainingHoursEstimate.new(:hours => 2.5, :estimated_on => Date.today.next)
assert_equal 2.5,
@item.remaining_hours,
diff --git a/test/unit/sprint_test.rb b/test/unit/sprint_test.rb
index 2e1c0c0..9e0d827 100644
--- a/test/unit/sprint_test.rb
+++ b/test/unit/sprint_test.rb
@@ -20,6 +20,7 @@ require File.dirname(__FILE__) + '/../test_helper'
class SprintTest < ActiveSupport::TestCase
fixtures :sprints
fixtures :products
+ fixtures :users
def setup
@sprint = Sprint.new(
@@ -28,10 +29,11 @@ class SprintTest < ActiveSupport::TestCase
:start => Date.today - 7,
:duration => 14,
:goals => "Things I'd like to accomplish.")
+ @developer = users(:mcpierce)
backlog_item = BacklogItem.new(:estimated_hours => 100)
backlog_item.tasks << Task.new(:hours => 50)
- backlog_item.remaining_hours = 50.0
+ backlog_item.update_remaining_hours(50.0,@developer)
@healthy_backlog = [ backlog_item ]
backlog_item = BacklogItem.new(:estimated_hours => 100)
--
1.6.0.2
15 years, 6 months
[PROJXP [PATCH] Users can view a burndown chart for a sprint. #7
by Darryl L. Pierce
Added a mapping for burndown charts. URLs will be in the format:
/report/burndown/[id]/[day]
where id is the sprint's id, and day is the day into the sprint
for the report.
The day argument is an optional parameter. If it is not included
then the current status of the sprint is reported.
This patch requires you to run a migration, and the gruff gem to be
installed.
---
app/controllers/backlog_controller.rb | 7 ++-
app/controllers/report_controller.rb | 56 ++++++++++++++++++++++
app/controllers/task_controller.rb | 1 -
app/controllers/user_story_controller.rb | 1 -
app/helpers/report_helper.rb | 2 +
app/models/backlog_item.rb | 18 ++++++-
app/models/sprint.rb | 22 +++++++++
app/views/report/burndown.html.erb | 3 +
app/views/sprint/view.html.erb | 33 +++++++------
config/environment.rb | 52 +++-----------------
config/routes.rb | 1 -
db/migrate/015_add_explicit_date_to_estimates.rb | 16 ++++++
db/schema.rb | 3 +-
test/fixtures/remaining_hours_estimates.yml | 2 +
test/functional/backlog_controller_test.rb | 15 +++++-
test/functional/report_controller_test.rb | 52 ++++++++++++++++++++
test/unit/backlog_item_test.rb | 2 +-
test/unit/sprint_test.rb | 4 +-
18 files changed, 217 insertions(+), 73 deletions(-)
create mode 100644 app/controllers/report_controller.rb
create mode 100644 app/helpers/report_helper.rb
create mode 100644 app/views/report/burndown.html.erb
create mode 100644 db/migrate/015_add_explicit_date_to_estimates.rb
create mode 100644 test/functional/report_controller_test.rb
diff --git a/app/controllers/backlog_controller.rb b/app/controllers/backlog_controller.rb
index 9e3ea1d..e033149 100644
--- a/app/controllers/backlog_controller.rb
+++ b/app/controllers/backlog_controller.rb
@@ -67,7 +67,8 @@ class BacklogController < ApplicationController
@backlog_item.remaining_hours_estimates << RemainingHoursEstimate.create(
:backlog_item_id => @backlog_item.id,
:user_id => @user.id,
- :hours => params[:hours])
+ :hours => params[:hours],
+ :estimated_on => Date.today)
end
rescue Exception => error
@@ -147,6 +148,7 @@ class BacklogController < ApplicationController
begin
BacklogItem.transaction do
@backlog_item.state = BacklogItem::STATE_COMPLETED
+ @backlog_item.update_remaining_hours(0.0, @user)
@backlog_item.save
end
@@ -170,6 +172,7 @@ class BacklogController < ApplicationController
BacklogItem.transaction do
@backlog_item.state = BacklogItem::STATE_CANCELED
@backlog_item.owner = nil
+ @backlog_item.update_remaining_hours(0.0, @user)
@backlog_item.save!
end
@@ -188,7 +191,7 @@ class BacklogController < ApplicationController
def reopen
if @backlog_item.user_can_reopen?(@user)
BacklogItem.transaction do
- @backlog_item.state = @backlog_item.owner ? BacklogItem::STATE_ASSIGNED : BacklogItem::PENDING
+ @backlog_item.state = @backlog_item.owner ? BacklogItem::STATE_ASSIGNED : BacklogItem::STATE_PENDING
@backlog_item.save!
redirect_to :action => :view, :id => @backlog_item.id
diff --git a/app/controllers/report_controller.rb b/app/controllers/report_controller.rb
new file mode 100644
index 0000000..c3ca4a1
--- /dev/null
+++ b/app/controllers/report_controller.rb
@@ -0,0 +1,56 @@
+# report_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/>.
+#
+
+# +ReportController+ allows users to view various reports.
+#
+class ReportController < ApplicationController
+ before_filter :load_sprint
+
+ # Generates a burndown report.
+ #
+ def burndown_graphic
+ if @sprint.can_view_burndown?
+ @data = @sprint.burndown_data
+
+ g = Gruff::Line.new('800x600')
+ g.title = "Burndown Chart For '#{(a)sprint.title}'"
+
+ g.font = File.expand_path('Courier.ttf', RAILS_ROOT)
+ g.data("Remaining hours", @data)
+ g.labels= {
+ 0 => @sprint.start.to_s(:date),
+ (@sprint.duration / 2) => (@sprint.start + (@sprint.duration / 2)).to_s(:date),
+ (@sprint.duration - 1) => (@sprint.start + (@sprint.duration - 1)).to_s(:date)}
+
+ send_data(g.to_blob, :disposition => 'inline', :type => 'image/png', :filename => "site-stats.png")
+ else
+ flash[:error] = 'Cannot view a burndown chart for this sprint.'
+ redirect_to :controller => :sprint, :action => :view, :id => @sprint.id
+ end
+ end
+
+ private
+
+ def load_sprint
+ @sprint = Sprint.find_by_id(params[:id])
+
+ unless @sprint
+ flash[:error] = 'Missing or invalid sprint id.'
+ redirect_to error_url
+ end
+ end
+end
diff --git a/app/controllers/task_controller.rb b/app/controllers/task_controller.rb
index 0692e6f..6c6e42b 100644
--- a/app/controllers/task_controller.rb
+++ b/app/controllers/task_controller.rb
@@ -42,7 +42,6 @@ class TaskController < ApplicationController
rescue ActiveRecord::RecordInvalid => error
flash[:message] = error.message
- puts ":::#{error.message}"
@task.valid?
render :action => :create
end
diff --git a/app/controllers/user_story_controller.rb b/app/controllers/user_story_controller.rb
index 9f5633d..83e567c 100644
--- a/app/controllers/user_story_controller.rb
+++ b/app/controllers/user_story_controller.rb
@@ -69,7 +69,6 @@ class UserStoryController < ApplicationController
end
rescue ActiveRecord::RecordInvalid => error
- puts ":::ERROR:#{error.message}"
@user_story.valid?
render :modify
end
diff --git a/app/helpers/report_helper.rb b/app/helpers/report_helper.rb
new file mode 100644
index 0000000..0847d3b
--- /dev/null
+++ b/app/helpers/report_helper.rb
@@ -0,0 +1,2 @@
+module ReportHelper
+end
diff --git a/app/models/backlog_item.rb b/app/models/backlog_item.rb
index 0eea0b3..55024c4 100644
--- a/app/models/backlog_item.rb
+++ b/app/models/backlog_item.rb
@@ -66,8 +66,22 @@ class BacklogItem < ActiveRecord::Base
remaining_hours_estimates.last.hours
end
- def remaining_hours=(hours)
- remaining_hours_estimates << RemainingHoursEstimate.new(:hours => hours)
+ def remaining_hours_for_date(date)
+ result = estimated_hours
+
+ remaining_hours_estimates.each do |estimate|
+ result = estimate.hours.to_f if estimate.estimated_on <= date
+ end
+
+ return result
+ end
+
+ def update_remaining_hours(hours, user)
+ remaining_hours_estimates <<
+ RemainingHoursEstimate.new(
+ :hours => hours,
+ :user_id => user.id,
+ :estimated_on => Date.today)
end
# Returns whether the given user can modify this backlog item.
diff --git a/app/models/sprint.rb b/app/models/sprint.rb
index 157396c..bf4a4ee 100644
--- a/app/models/sprint.rb
+++ b/app/models/sprint.rb
@@ -100,6 +100,12 @@ class Sprint < ActiveRecord::Base
backlog_items.inject(0) { |sum, item| sum + item.remaining_hours}
end
+ # Returns the number of hours remaining for the specified day.
+ #
+ def remaining_hours_for_day(day)
+ backlog_items.inject(0) { |sum, item| sum + item.remaining_hours_for_date(start + day) }
+ end
+
# Returns whether the specified user can modify this sprint.
#
def user_can_modify(user)
@@ -118,6 +124,22 @@ class Sprint < ActiveRecord::Base
status == STATUS_ACTIVE
end
+ # Returns whether a burndown chart can be viewed for this sprint.
+ #
+ def can_view_burndown?
+ status != STATUS_PLANNED
+ end
+
+ # Returns the data as of the given day into the sprint.
+ #
+ def burndown_data
+ data = []
+
+ (0..duration).each { |day| data[day] = remaining_hours_for_day(day) }
+
+ return data
+ end
+
# Returns whether the sprint is in a healthy state or not.
#
def healthy?
diff --git a/app/views/report/burndown.html.erb b/app/views/report/burndown.html.erb
new file mode 100644
index 0000000..b5fa23f
--- /dev/null
+++ b/app/views/report/burndown.html.erb
@@ -0,0 +1,3 @@
+<img src="<%= url_for :action => :burndown_graphic, :id => @sprint.id %>"
+ alt="Burndown"
+ align="center" />
\ No newline at end of file
diff --git a/app/views/sprint/view.html.erb b/app/views/sprint/view.html.erb
index cfa0a58..c6a1659 100644
--- a/app/views/sprint/view.html.erb
+++ b/app/views/sprint/view.html.erb
@@ -1,10 +1,13 @@
<div style="width: 100%; overflow: auto">
<div style="float: left; width: 33%;">
<div class="toolbar">
-
+
<%= link_to "Edit", :action => :modify, :id => @sprint %>
<%= link_to "Populate", :action => :populate, :id => @sprint %>
-
+ <% if @sprint.can_view_burndown? %>
+ <%= link_to "Burndown", :controller => :report, :action => :burndown, :id => @sprint.id %>
+ <% end %>
+
</div>
<table class="details">
<thead>
@@ -12,14 +15,14 @@
<th class="title" colspan="2"><%= @sprint.title %></th>
</tr>
</thead>
-
+
<tbody>
<tr>
<td class="label">Status:</td>
- <td class="value">
+ <td class="value">
<% if @sprint.user_can_modify(@user) %>
<% form_tag(:action => :status, :id => @sprint.id) do %>
- <%= select_tag "status",
+ <%= select_tag "status",
options_for_select(Sprint::STATUS_TEXT, @sprint.status) %>
<%= submit_tag "Apply" %>
<% end %>
@@ -28,36 +31,36 @@
<% end %>
</td>
</tr>
-
+
<tr>
<td class="label">Starts:</td>
<td class="value"><%= @sprint.start.to_s(:date) %></td>
</tr>
-
+
<tr>
<td class="label">Ends:</td>
<td class="value"><%= @sprint.end_date.to_s(:date) %>
</tr>
-
+
<tr>
<td class="label">Hours E/A/R:</td>
<td class="value"><%= "#{@sprint.estimated_hours}/#{@sprint.actual_hours}/#{(a)sprint.remaining_hours}" %></td>
</tr>
-
+
<tr>
<td class="text" colspan="2"><%= simple_format @sprint.goals %></td>
</tr>
</tbody>
-
+
</table>
</div>
-
+
<div style="width: 66%; float:left;">
-
+
<%= will_paginate @backlog_items %>
-
-
- <%= render :partial => 'backlog/list',
+
+
+ <%= render :partial => 'backlog/list',
:object => @backlog_items.sort {|item1, item2| item1.user_story.priority <=> item2.user_story.priority},
:locals => {:title => 'Sprint Backlog'}%>
</div>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..dec56ec 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -1,25 +1,25 @@
# environment.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/>.
-#
+#
# Be sure to restart your server when you modify this file
# Uncomment below to force Rails into production mode when you don't control
-# web/app server and can't set it the proper way ENV['RAILS_ENV'] ||=
-# 'production'
+# web/app server and can't set it the proper way
+# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
# #RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
@@ -28,50 +28,12 @@
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
- # Settings in config/environments/* take precedence over those specified here.
- # Application configuration should go into files in config/initializers -- all
- # .rb files in that directory are automatically loaded. See
- # Rails::Configuration for more options.
-
- # Skip frameworks you're not going to use (only works if using vendor/rails).
- # To use Rails without a database, you must remove the Active Record framework
- # config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
-
- # Only load the plugins named here, in the order given. By default, all
- # plugins in vendor/plugins are loaded in alphabetical order. :all can be used
- # as a placeholder for all plugins not explicitly named config.plugins = [
- # :exception_notification, :ssl_requirement, :all ]
-
- # Add additional load paths for your own custom dirs config.load_paths += %W(
- # #{RAILS_ROOT}/extras )
-
- # Force all environments to use the same logger level (by default production
- # uses :info, the others :debug) config.log_level = :debug
-
- # Your secret key for verifying cookie session data integrity. If you change
- # this key, all old sessions will become invalid! Make sure the secret is at
- # least 30 characters and all random, no regular words or you'll be exposed to
- # dictionary attacks.
config.action_controller.session = {
:session_key => '_chiroxp_session',
:secret => 'bb5e22a8065951948272bccbeff6c1e1fa1eff29e85dabcefe7577b68795d9e42cfc9a18426f84aee6722bb4859bf8b144a98fa58891e6c1f215dc3b6f38d2b3'
}
- # Use the database for sessions instead of the cookie-based default, which
- # shouldn't be used to store highly confidential information (create the
- # session table with 'rake db:sessions:create')
- # config.action_controller.session_store = :active_record_store
-
- # Use SQL instead of Active Record's schema dumper when creating the test
- # database. This is necessary if your schema can't be completely dumped by the
- # schema dumper, like if you have constraints or database-specific column
- # types config.active_record.schema_format = :sql
-
- # Activate observers that should always be running
- # config.active_record.observers = :cacher, :garbage_collector
-
- # Make Active Record use UTC-base instead of local time
- # config.active_record.default_timezone = :utc
+ config.gem "gruff"
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
diff --git a/config/routes.rb b/config/routes.rb
index e1f81cc..1108059 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -23,7 +23,6 @@ ActionController::Routing::Routes.draw do |map|
# Error handling
map.error "/error", :controller => 'home', :action => 'error'
-
# Install the default routes as the lowest priority.
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
diff --git a/db/migrate/015_add_explicit_date_to_estimates.rb b/db/migrate/015_add_explicit_date_to_estimates.rb
new file mode 100644
index 0000000..f300931
--- /dev/null
+++ b/db/migrate/015_add_explicit_date_to_estimates.rb
@@ -0,0 +1,16 @@
+class AddExplicitDateToEstimates < ActiveRecord::Migration
+ def self.up
+ add_column :remaining_hours_estimates, :estimated_on, :datetime
+
+ RemainingHoursEstimate.find(:all).each do |estimate|
+ estimate.estimated_on = estimate.created_at
+ estimate.save!
+ end
+
+ change_column :remaining_hours_estimates, :estimated_on, :datetime, :null => false
+ end
+
+ def self.down
+ remove_column :remaining_hours_estimates, :estimated_on
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index c773644..4a20449 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 => 14) do
+ActiveRecord::Schema.define(:version => 15) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -62,6 +62,7 @@ ActiveRecord::Schema.define(:version => 14) do
t.decimal "hours", :precision => 5, :scale => 2, :null => false
t.datetime "created_at"
t.datetime "updated_at"
+ t.datetime "estimated_on", :null => false
end
create_table "roles", :force => true do |t|
diff --git a/test/fixtures/remaining_hours_estimates.yml b/test/fixtures/remaining_hours_estimates.yml
index 6e2e09b..b5ecd13 100644
--- a/test/fixtures/remaining_hours_estimates.yml
+++ b/test/fixtures/remaining_hours_estimates.yml
@@ -2,8 +2,10 @@ owned_backlog_item_remaining_one:
backlog_item_id: <%= Fixtures.identify(:owned_backlog_item) %>
user_id: <%= Fixtures.identify(:mcpierce) %>
hours: 2.5
+ estimated_on: <%= Date.today.to_s(:db) %>
owned_backlog_item_remaining_two:
backlog_item_id: <%= Fixtures.identify(:owned_backlog_item) %>
user_id: <%= Fixtures.identify(:mcpierce) %>
hours: 4.5
+ estimated_on: <%= Date.today.next.to_s(:db) %>
diff --git a/test/functional/backlog_controller_test.rb b/test/functional/backlog_controller_test.rb
index 4657b2d..cb2b041 100644
--- a/test/functional/backlog_controller_test.rb
+++ b/test/functional/backlog_controller_test.rb
@@ -38,8 +38,10 @@ class BacklogControllerTest < ActionController::TestCase
@completed_backlog_item = backlog_items(:closed_backlog_item)
flunk "Closed item should have a closed state!" unless @completed_backlog_item.state == BacklogItem::STATE_COMPLETED
+
@open_backlog_item = @owned_backlog_item
flunk "Open item should have an open state!" unless @open_backlog_item.state == BacklogItem::STATE_ASSIGNED
+
@task = tasks(:created_login_controller)
@sprint = @owned_backlog_item.sprint
end
@@ -282,6 +284,7 @@ class BacklogControllerTest < ActionController::TestCase
# Ensures that remaining hours must be a non-zero value.
#
def test_remaining_with_nonnumeric_hours
+ old_hours = @owned_backlog_item.remaining_hours.to_f
post :remaining,
{
:id => @owned_backlog_item.id,
@@ -290,7 +293,9 @@ class BacklogControllerTest < ActionController::TestCase
{:user_id => @owned_backlog_item.owner_id}
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
- assert flash.has_key?(:message)
+ result = BacklogItem.find_by_id((a)owned_backlog_item.id)
+ assert_equal old_hours, result.remaining_hours.to_f,
+ "Remaining hours should not have changed."
end
# Ensures that a negative remaining hours estimate is rejected.
@@ -310,6 +315,8 @@ class BacklogControllerTest < ActionController::TestCase
# Ensures that a zero hours remaining estimate is rejected.
#
def test_remaining_with_zero_hours
+ old_hours = @owned_backlog_item.remaining_hours
+
post :remaining,
{
:id => @owned_backlog_item.id,
@@ -318,7 +325,9 @@ class BacklogControllerTest < ActionController::TestCase
{:user_id => @owned_backlog_item.owner_id}
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
- assert flash.has_key?(:message)
+ result = BacklogItem.find_by_id((a)owned_backlog_item.id)
+ assert_equal old_hours.to_f, result.remaining_hours.to_f,
+ 'Remaining hours should not have changed.'
end
# Ensures that someone who is not the backlog item owner can't update the
@@ -354,7 +363,7 @@ class BacklogControllerTest < ActionController::TestCase
assert_redirected_to :action => :view, :id => @owned_backlog_item.id
result = BacklogItem.find_by_id((a)owned_backlog_item.id)
- assert_equal 2.5, result.remaining_hours, 'Remaining hours not updated correctly.'
+ assert_equal 2.5, result.remaining_hours.to_f, 'Remaining hours not updated correctly.'
end
# Ensures that anonymous users cannot reopen a closed task.
diff --git a/test/functional/report_controller_test.rb b/test/functional/report_controller_test.rb
new file mode 100644
index 0000000..6957fe5
--- /dev/null
+++ b/test/functional/report_controller_test.rb
@@ -0,0 +1,52 @@
+# report_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 ReportControllerTest < ActionController::TestCase
+ fixtures :sprints
+
+ def setup
+ @pending_sprint = sprints(:inactive_sprint)
+ @sprint = sprints(:initial_development_sprint)
+ end
+
+ # Ensures that an error occurs when no sprint id was provided.
+ #
+ def test_burndown_graphic_without_sprint_id
+ get :burndown_graphics
+
+ assert_redirected_to error_url
+ end
+
+ # Ensures that trying to print a burndown report for a pending sprint fails.
+ #
+ def test_burndown_graphic_fails_for_pending_sprint
+ get :burndown_graphic, {:id => @pending_sprint.id}
+
+ assert_redirected_to :controller => :sprint, :action => :view, :id => @pending_sprint.id
+ end
+
+ # Ensures that a burndown chart works as expected.
+ #
+ def test_burndown_graphic
+ get :burndown_graphic, {:id => @sprint.id}
+
+ assert_response :success
+ assert assigns['data'], "Didn't generate the data needed for a report."
+ end
+end
diff --git a/test/unit/backlog_item_test.rb b/test/unit/backlog_item_test.rb
index fd24efa..c3cbc1b 100644
--- a/test/unit/backlog_item_test.rb
+++ b/test/unit/backlog_item_test.rb
@@ -67,7 +67,7 @@ class BacklogItemTest < ActiveSupport::TestCase
#
def test_remaining_hours_when_updated
@item.estimated_hours = 5.0
- @item.remaining_hours_estimates << RemainingHoursEstimate.new(:hours => 2.5)
+ @item.remaining_hours_estimates << RemainingHoursEstimate.new(:hours => 2.5, :estimated_on => Date.today.next)
assert_equal 2.5,
@item.remaining_hours,
diff --git a/test/unit/sprint_test.rb b/test/unit/sprint_test.rb
index 2e1c0c0..9e0d827 100644
--- a/test/unit/sprint_test.rb
+++ b/test/unit/sprint_test.rb
@@ -20,6 +20,7 @@ require File.dirname(__FILE__) + '/../test_helper'
class SprintTest < ActiveSupport::TestCase
fixtures :sprints
fixtures :products
+ fixtures :users
def setup
@sprint = Sprint.new(
@@ -28,10 +29,11 @@ class SprintTest < ActiveSupport::TestCase
:start => Date.today - 7,
:duration => 14,
:goals => "Things I'd like to accomplish.")
+ @developer = users(:mcpierce)
backlog_item = BacklogItem.new(:estimated_hours => 100)
backlog_item.tasks << Task.new(:hours => 50)
- backlog_item.remaining_hours = 50.0
+ backlog_item.update_remaining_hours(50.0,@developer)
@healthy_backlog = [ backlog_item ]
backlog_item = BacklogItem.new(:estimated_hours => 100)
--
1.6.0.2
15 years, 6 months
[PROJXP [PATCH] Emails are sent when no activity is recorded. #10
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/user_mailer.rb | 10 +++++
.../user_mailer/no_activity_recorded.html.erb | 6 +++
config/environment.rb | 5 ++-
config/initializers/schedules.rb | 37 ++++++++++++++++++++
4 files changed, 57 insertions(+), 1 deletions(-)
create mode 100644 app/views/user_mailer/no_activity_recorded.html.erb
create mode 100644 config/initializers/schedules.rb
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index 73308af..8d60671 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -7,4 +7,14 @@ class UserMailer < ActionMailer::Base
subject "Your password"
body :user => user, :new_password => new_password
end
+
+ # Send an e-mail to an user an notify him that no-activity has been detected
+ # for some backlog items.
+ #
+ def no_activity_recorded(user, backlog_items)
+ recipients user.email
+ from "no_reply(a)projxp.org" # TODO Email must be edit
+ subject "No activity has been detected"
+ body :user => user, :backlog_items => backlog_items
+ end
end
diff --git a/app/views/user_mailer/no_activity_recorded.html.erb b/app/views/user_mailer/no_activity_recorded.html.erb
new file mode 100644
index 0000000..e4acd3c
--- /dev/null
+++ b/app/views/user_mailer/no_activity_recorded.html.erb
@@ -0,0 +1,6 @@
+Dear <%= @user.display_name %>,
+
+No activities was detected on this backlogs:
+<% @backlog_items.each do |backlog_item|%>
+<%= backlog_item.user_story.title %>
+<% end %>
diff --git a/config/environment.rb b/config/environment.rb
index af8a593..1687102 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -72,6 +72,9 @@ Rails::Initializer.run do |config|
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
+
+ # Gems
+ config.gem 'openwferu-scheduler', :lib => 'openwfe/util/scheduler'
end
ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
@@ -82,7 +85,7 @@ ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
# Mail configuration.
# Please complete the config file are locate at /config/mailer.yml
-#
+#
require "smtp_tls"
mailer_config = File.open("#{RAILS_ROOT}/config/mailer.yml")
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
new file mode 100644
index 0000000..287756c
--- /dev/null
+++ b/config/initializers/schedules.rb
@@ -0,0 +1,37 @@
+require 'fastthread'
+require 'openwfe/util/scheduler'
+include OpenWFE
+
+# Initialize a threads array
+threads = []
+
+threads << Thread.new do
+ scheduler = Scheduler.new
+ scheduler.start
+
+ # Do this everyday at 10:00 am
+ scheduler.schedule('0 8 * * *') do
+
+ user_no_activity_on_backlog_items = {}
+ BacklogItem.find_all_by_state(BacklogItem::STATE_ASSIGNED).each do |backlog_item|
+ backlog_item.tasks.each do |task|
+ if task.created_at.to_date < Date.yesterday
+ backlog_item_owner = backlog_item.owner
+ user_no_activity_on_backlog_items[backlog_item_owner] ||= []
+ user_no_activity_on_backlog_items[backlog_item_owner] << backlog_item
+ end
+ end
+ end
+
+ # Send the e-mail
+ user_no_activity_on_backlog_items.each do |owner, backlog_items|
+ UserMailer.deliver_no_activity_recorded(owner, backlog_items)
+ end
+
+ end
+
+ scheduler.join
+end
+
+# Run all threads
+threads.each { |thread| thread.run }
\ No newline at end of file
--
1.5.2.4
15 years, 6 months