[PATCH] Users can request their verification be resent. #72
by Darryl L. Pierce
If, on the verification page, the user clicks the "Resend" button,
a new email is sent to their account.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/users_controller.rb | 32 ++++++++++++--------
app/views/users/verify.html.erb | 45 ++++++++++++++++++-----------
public/stylesheets/forms.css | 3 +-
test/functional/users_controller_test.rb | 17 ++++++++++-
4 files changed, 64 insertions(+), 33 deletions(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 15c7894..3837436 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -124,22 +124,28 @@ class UsersController < ApplicationController
respond_to do |format|
if @this_user.id == @user.id
if !(a)user.verified?
- @token = params[:token]
+ if params[:resend]
+ flash[:message] = "Sent another verification email to #{(a)this_user.email}."
+ UserMailer.deliver_email_verification(@this_user,(a)this_user.verification.token)
+ format.html
+ else
+ @token = params[:token]
- if @token && @user.verify(@token)
- User.transaction do
- @user.verification.destroy
+ if @token && @user.verify(@token)
+ User.transaction do
+ @user.verification.destroy
- flash[:message] = "#{(a)user.email} is now verified."
- format.html { redirect_to user_path(@user) }
+ flash[:message] = "#{(a)user.email} is now verified."
+ format.html { redirect_to user_path(@user) }
+ end
+ else
+ @title = "Email Verification For #{(a)user.email}"
+ flash[:error] = "Missing or invalid verification token."
+ format.html
end
- else
- @title = "Email Verification For #{(a)user.email}"
- flash[:error] = "Missing or invalid verification token."
- format.html
end
else
- flash[:error] = "Your account has already been validated."
+ flash[:error] = "Your account has already been verified."
format.html { redirect_to user_path(@user) }
end
else
diff --git a/app/views/users/verify.html.erb b/app/views/users/verify.html.erb
index e7426ff..5a5df04 100644
--- a/app/views/users/verify.html.erb
+++ b/app/views/users/verify.html.erb
@@ -1,19 +1,30 @@
-<% form_for :user, :url => email_verification_path(:id => @user, :token => nil) do |form| %>
- <table class="edit">
- <tr>
- <td class="label-required">Email address:</td>
- <td class="value"><%= @user.email %></td>
- </tr>
+<fieldset id="verify">
+ <legend>Verify Your Account</legend>
+ <% form_for :user, :url => email_verification_path(:id => @user, :token => nil) do |form| %>
+ <table class="edit">
+ <colgroup>
+ <col class="label" />
+ <col class="value" />
+ </colgroup>
- <tr>
- <td class="label-required">Token</td>
- <td class="value"><%= text_field_tag :token, @token %>
- </tr>
+ <tbody>
+ <tr>
+ <td class="label-required">Email address</td>
+ <td class="value"><%= @user.email %></td>
+ </tr>
- <tr>
- <td class="buttons" colspan="2">
- <%= submit_tag "Submit" %>
- </td>
- </tr>
- </table>
-<% end %>
+ <tr>
+ <td class="label-required">Token</td>
+ <td class="value"><%= text_field_tag :token, @token %>
+ </tr>
+
+ <tr>
+ <td class="buttons" colspan="2">
+ <%= submit_tag "Submit", :name => :submit %>
+ <%= submit_tag "Resend", :name => :resend %>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ <% end %>
+</fieldset>
diff --git a/public/stylesheets/forms.css b/public/stylesheets/forms.css
index ce9b21d..07dc248 100644
--- a/public/stylesheets/forms.css
+++ b/public/stylesheets/forms.css
@@ -4,8 +4,7 @@
}
fieldset {
- margin-top: 10px;
- margin-bottom: 10px;
+ margin: 10px 0px 10px 15px;
background-color: #fffffe;
max-width: 100%;
width: 2em;
diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb
index 0207fdd..af4fb7e 100644
--- a/test/functional/users_controller_test.rb
+++ b/test/functional/users_controller_test.rb
@@ -288,9 +288,24 @@ class UsersControllerTest < ActionController::TestCase
"User should not be verified."
end
+ # Ensures that a user can properly resend a verification token.
+ def test_verify_with_resend_request
+ post :verify,
+ {:id => @unverified_user.id, :resend => true},
+ {:user_id => @unverified_user.id}
+
+ assert_response :success
+ assert !User.find_by_id((a)unverified_user.id).verified?,
+ "User should not be verified."
+
+ email = @emails.first
+ assert email, "No email was generated."
+ assert_equal @unverified_user[:email], email.to[0], "Email sent to wrong user."
+ end
+
# Ensures that verification works as expected.
def test_verify
- get :verify,
+ post :verify,
{:id => @unverified_user.id, :token => @unverified_user.verification.token},
{:user_id => @unverified_user.id}
--
1.6.0.2
15 years, 4 months
Preparing for release 0.0.1
by Darryl L. Pierce
I think that, with the feature set with we have currently, we're
nearly ready for a release.
We have three outstanding items on our backlog:
1. patch that's in flight now waiting for an ACK or feedback (#65,
sending daily updates to the product mailing list),
2. a patch that received feedback and is waiting for an update (#71,
sprints with tasks cannot be moved to the planning state), and
3. one item with no owner (#72, resending email verifications for
registrations).
Looking at our outstanding bugs we have one defect, regarding the user
verification scheduler failing. Though I'm sure we have a few other
bugs creeping around out there.
So, with all of this in mind, I think we can start planning our first
official release. I'm going to start smoke testing things after my
patches get fixed up and pushed and start feeding bugs into Trac.
Also, we'll need to write up deployment documentation for various
OS's, such as Windows, Linux and Mac OS.
Thoughts?
--
Darryl L. Pierce <mcpierce(a)gmail.com>
Visit the Infobahn Offramp: <http://mcpierce.multiply.com>
"Bury me next to my wife. Nothing too fancy..." - Ulysses S. Grant
15 years, 4 months
[PATCH] Add option to send daily updates to the product list. #65
by Darryl L. Pierce
This patch fixes the nil error raised for users with no tasks to report.
Added a new column to the notifications table to toggle sending
the notifications.
Updated the user's profile page to include an option to toggle this
on and off. Also changed the notifications view to be more intuitive.
When daily updates are collected, then all affected products are CC'd
with the user's daily update. CC'ing product lists requires the user
to have daily updates enabled.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
config/initializers/schedules.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
index 83be588..b1fc4f2 100644
--- a/config/initializers/schedules.rb
+++ b/config/initializers/schedules.rb
@@ -63,7 +63,7 @@ threads["daily updates"] = Thread.new do
end
User.find(:all).each do |user|
- if user.notifications.daily_updates
+ if user.notifications.daily_updates && tasks_performed[user]
cc_list = []
if user.notifications.updates_to_product_list
--
1.6.0.2
15 years, 4 months
[PATCH] Add option to send daily updates to the product list. #65
by Darryl L. Pierce
Added a new column to the notifications table to toggle sending
the notifications.
Updated the user's profile page to include an option to toggle this
on and off. Also changed the notifications view to be more intuitive.
When daily updates are collected, then all affected products are CC'd
with the user's daily update. CC'ing product lists requires the user
to have daily updates enabled.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/models/user_mailer.rb | 3 +-
app/views/users/_notifications.html.erb | 27 ++++++++++++---
config/initializers/schedules.rb | 33 +++++++++++++------
.../022_add_send_notifications_to_product_list.rb | 26 +++++++++++++++
db/schema.rb | 3 +-
5 files changed, 73 insertions(+), 19 deletions(-)
create mode 100644 db/migrate/022_add_send_notifications_to_product_list.rb
diff --git a/app/models/user_mailer.rb b/app/models/user_mailer.rb
index e830463..5609dc8 100644
--- a/app/models/user_mailer.rb
+++ b/app/models/user_mailer.rb
@@ -58,8 +58,9 @@ class UserMailer < ActionMailer::Base
end
# Sends an email to a user letting him know his daily activities.
- def daily_updates(user, open_items, completed_items, task_performed)
+ def daily_updates(user, cc_list, open_items, completed_items, task_performed)
recipients user.email
+ cc cc_list
from MAIL_CONFIG[:from]
subject "Daily updates for #{user.display_name}"
body :user => user, :open_items => open_items,
diff --git a/app/views/users/_notifications.html.erb b/app/views/users/_notifications.html.erb
index 06b34fb..79e9518 100644
--- a/app/views/users/_notifications.html.erb
+++ b/app/views/users/_notifications.html.erb
@@ -1,25 +1,40 @@
<% form_for(:notifications, @this_user.notifications, :url => notifications_user_path(@this_user)) do |form| %>
<table class="edit">
+ <colgroup>
+ <col class="value" />
+ </colgroup>
+
<thead>
<tr>
- <th class="title" colspan="2">Email Notifications</th>
+ <th class="title">Email Notifications</th>
</tr>
</thead>
<tbody>
<tr>
- <td class="label">Daily scrum email</td>
- <td class="value"><%= form.check_box :daily_updates %></td>
+ <td class="value">
+ <%= form.check_box :daily_updates %>
+ <%= form.label :daily_updates, "Send a daily updates." %>
+ </td>
</tr>
<tr>
- <td class="label">Task reminders</td>
- <td class="value"><%= form.check_box :task_reminders %>
+ <td class="value">
+ <%= form.check_box :updates_to_product_list %>
+ <%= form.label :updates_to_product_list, "Send updates to product list (requires daily updates be enabled)." %>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="value">
+ <%= form.check_box :task_reminders %>
+ <%= form.label :task_reminders, "Send daily task update reminders." %>
+ </td>
</tr>
<tr>
- <td class="buttons" colspan="2">
+ <td class="buttons">
<%= submit_tag "Update" %>
</td>
</tr>
diff --git a/config/initializers/schedules.rb b/config/initializers/schedules.rb
index 07b9618..83be588 100644
--- a/config/initializers/schedules.rb
+++ b/config/initializers/schedules.rb
@@ -1,18 +1,18 @@
# schedules.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 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.
+# 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/>.
+# 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 'fastthread'
require 'openwfe/util/scheduler'
@@ -64,7 +64,18 @@ threads["daily updates"] = Thread.new do
User.find(:all).each do |user|
if user.notifications.daily_updates
- UserMailer.deliver_daily_updates(user, open_items[user],
+ cc_list = []
+
+ if user.notifications.updates_to_product_list
+ tasks_performed[user].each do |task|
+ product = task.backlog_item.sprint.product
+ if product.has_mailing_list? && !cc_list.include?(product.mailing_list)
+ cc_list << product.mailing_list
+ end
+ end
+ end
+
+ UserMailer.deliver_daily_updates(user, cc_list, open_items[user],
completed_items[user], tasks_performed[user])
end
end
diff --git a/db/migrate/022_add_send_notifications_to_product_list.rb b/db/migrate/022_add_send_notifications_to_product_list.rb
new file mode 100644
index 0000000..2c48cc7
--- /dev/null
+++ b/db/migrate/022_add_send_notifications_to_product_list.rb
@@ -0,0 +1,26 @@
+# 022_add_send_notifications_to_product_list.rb
+# Copyright (C) 2008, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+class AddSendNotificationsToProductList < ActiveRecord::Migration
+ def self.up
+ add_column :notifications, :updates_to_product_list, :boolean, :default => false
+ end
+
+ def self.down
+ remove_column :notifications, :updates_to_product_list
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6c86037..90c8c4a 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 => 21) do
+ActiveRecord::Schema.define(:version => 22) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -31,6 +31,7 @@ ActiveRecord::Schema.define(:version => 21) do
t.boolean "daily_updates"
t.datetime "created_at"
t.datetime "updated_at"
+ t.boolean "updates_to_product_list", :default => false
end
create_table "product_roles", :force => true do |t|
--
1.6.0.2
15 years, 4 months
[PATCH] Added last logged in date to users table. #67
by Darryl L. Pierce
I refactored the patch to account for some bug fixes I found while playing
around with the new functionality.
This patch requires that you do a migration.
Adds a new column to the users table for the user's last date and
time of login. Displays this value in the user list.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/home_controller.rb | 7 ++-
app/controllers/projects_controller.rb | 44 ++++++++------------
app/controllers/users_controller.rb | 1 +
app/helpers/application_helper.rb | 10 +++--
app/views/users/_list.html.erb | 3 +
db/migrate/023_add_last_logged_in_date_to_users.rb | 26 ++++++++++++
db/schema.rb | 3 +-
test/fixtures/users.yml | 7 +++
test/functional/home_controller_test.rb | 20 ++++-----
9 files changed, 76 insertions(+), 45 deletions(-)
create mode 100644 db/migrate/023_add_last_logged_in_date_to_users.rb
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 15d708c..2f9085d 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -40,11 +40,9 @@ class HomeController < ApplicationController
# dashboard.
#
# On failure, the user is reshown the login page.
- #
def login
session[:user_id] = nil
- # if the user was doing a login, then process the values submitted
if request.post?
user = User.authenticate(params[:email], params[:password])
@@ -52,6 +50,11 @@ class HomeController < ApplicationController
session[:user_id] = user.id
uri = session[:original_uri]
session[:original_uri] = nil
+ user.last_logged_in = DateTime.now
+
+ User.transaction do
+ user.save
+ end
redirect_to(uri || dashboard_url)
else
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 50329cb..fa219c9 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -72,20 +72,15 @@ class ProjectsController < ApplicationController
if @user.can_create_projects?
@project = Project.new(params[:project])
- begin
- Project.transaction do
- if @project.save
- flash[:message] = "Project '#{(a)project.name}' created!"
- format.html { redirect_to params[:source] ? params[:source] : project_url(@project) }
- else
- @title = "New Project"
- @project.valid?
- format.html { render :action => "new" }
- end
+ Project.transaction do
+ if @project.save
+ flash[:message] = "Project '#{(a)project.name}' created!"
+ format.html { redirect_to params[:source] ? params[:source] : project_url(@project) }
+ else
+ @title = "New Project"
+ @project.valid?
+ format.html { render :action => "new" }
end
- rescue Exception => error
- flash[:error] = "ERROR: #{error.message}"
- format.html { redirect_to params[:source] ? params[:source] : error_url }
end
else
flash[:error] = "You are not authorized to create projects."
@@ -98,21 +93,16 @@ class ProjectsController < ApplicationController
def update
respond_to do |format|
if @project.can_edit?(@user)
- begin
- Project.transaction do
- @project.update_attributes(params[:project])
- if @project.save!
- flash[:message] = "Project was successfully updated."
- format.html { redirect_to params[:source] ? params[:source] : project_path(@project) }
- else
- @title = "#{(a)project.name} (Edit)"
- @project.valid?
- format.html { render :action => 'edit'}
- end
+ Project.transaction do
+ @project.update_attributes(params[:project])
+ if @project.save!
+ flash[:message] = "Project was successfully updated."
+ format.html { redirect_to params[:source] ? params[:source] : project_path(@project) }
+ else
+ @title = "#{(a)project.name} (Edit)"
+ @project.valid?
+ format.html { render :action => 'edit'}
end
- rescue Exception => error
- flash[:error] = "ERROR: #{error.message}"
- format.html { redirect_to error_url }
end
else
flash[:error] = "You are not authorized to edit this project."
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 15c7894..5966bcb 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -63,6 +63,7 @@ class UsersController < ApplicationController
respond_to do |format|
if (@user == nil) || (@user.create_users?)
@this_user = User.new(params[:user])
+ @this_user.last_logged_in = DateTime.new
@this_user.privileges = UserPrivilege.new
@this_user.notifications = Notifications.new
@this_user.verification = UserVerification.new(
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 9e81b48..47e76bb 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -37,10 +37,12 @@ module ApplicationHelper
# Displays a date or date and time.
def show_date(datetime, include_time = false)
- if include_time
- datetime.strftime("%m/%d/%Y %I:%M:%S %P")
- else
- datetime.strftime("%m/%d/%Y")
+ if datetime
+ if include_time
+ datetime.strftime("%m/%d/%Y %I:%M:%S %P")
+ else
+ datetime.strftime("%m/%d/%Y")
+ end
end
end
diff --git a/app/views/users/_list.html.erb b/app/views/users/_list.html.erb
index d4bb89f..c36e77e 100644
--- a/app/views/users/_list.html.erb
+++ b/app/views/users/_list.html.erb
@@ -7,6 +7,7 @@
<col class="number" />
<col class="number" />
<col class="date" />
+ <col class="date" />
<col class="actions" />
</colgroup>
@@ -18,6 +19,7 @@
<th>Email</th>
<th>Backlog</th>
<th>Roles</th>
+ <th>Last On</th>
<th>Since</th>
<th>Actions</th>
</tr>
@@ -34,6 +36,7 @@
<td><%= mail_to user.email, user.display_name %></td>
<td><%= link_to "#{user.backlog.size} items", backlog_user_path(user) %>
<td><%= link_to "#{user.product_roles.size} roles", roles_user_path(user) %></td>
+ <td><%= show_date(user.last_logged_in) %></td>
<td><%= show_date(user.created_at) %></td>
<td>
<%= link_to(image_tag("icons/view.png", :alt => "View user..."), user_path(user)) %>
diff --git a/db/migrate/023_add_last_logged_in_date_to_users.rb b/db/migrate/023_add_last_logged_in_date_to_users.rb
new file mode 100644
index 0000000..824f7f5
--- /dev/null
+++ b/db/migrate/023_add_last_logged_in_date_to_users.rb
@@ -0,0 +1,26 @@
+# 023_add_last_logged_in_date_to_users.rb
+# Copyright (C) 2008, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+class AddLastLoggedInDateToUsers < ActiveRecord::Migration
+ def self.up
+ add_column :users, :last_logged_in, :datetime, :null => false
+ end
+
+ def self.down
+ remove_column :users, :last_logged_in
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 90c8c4a..024b1cd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 22) do
+ActiveRecord::Schema.define(:version => 23) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -174,6 +174,7 @@ ActiveRecord::Schema.define(:version => 22) do
t.text "introduction"
t.datetime "created_at"
t.datetime "updated_at"
+ t.datetime "last_logged_in", :null => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index 6a204c8..dfefb66 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -6,6 +6,7 @@ admin:
introduction: Can't you see I'm busy?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('admin', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
projxp_owner:
email: admin(a)projxp.org
@@ -13,6 +14,7 @@ projxp_owner:
introduction: Wassup?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('bonk', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
teatime_owner:
email: admin(a)teatime.org
@@ -20,6 +22,7 @@ teatime_owner:
introduction: I'd like a nice cuppa.
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('earlgrey', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
mcpierce:
email: mcpierce(a)gmail.com
@@ -27,6 +30,7 @@ mcpierce:
introduction: How are you?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('farkle', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
jdonuts:
email: jdonuts(a)gmail.com
@@ -34,6 +38,7 @@ jdonuts:
introduction: How's it going, eh?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('jelly', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
celliot:
email: celliot(a)gmail.com
@@ -41,6 +46,7 @@ celliot:
introduction: Get a life.
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('loser', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
unverified_user:
email: unverified(a)newuser.com
@@ -48,3 +54,4 @@ unverified_user:
introduction: Am I who I say I am?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('unverified', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
diff --git a/test/functional/home_controller_test.rb b/test/functional/home_controller_test.rb
index 94574b5..aafde7a 100644
--- a/test/functional/home_controller_test.rb
+++ b/test/functional/home_controller_test.rb
@@ -33,7 +33,6 @@ class HomeControllerTest < ActionController::TestCase
# Ensures that anonymous users are sent to the login page when they try to
# view the dashboard.
- #
def test_dashboard_for_anonymous_user
get :dashboard
@@ -42,7 +41,6 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that authenticated users are shown their dashboard.
- #
def test_dashboard_for_authenticated_user
get :dashboard, nil, {:user_id => @authenticated_user.id}
@@ -52,30 +50,31 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that a failed login redirects back to the login action.
- #
def test_login_failure
get :dashboard
- assert_redirected_to :action => :login
+ assert_redirected_to login_path
post :login, {:email => 'mcpierce(a)gmail.com',
:password => 'klefar' }
- assert_redirected_to :action => :login
+ assert_response :success
+ assert !session[:user_id], "User ID should not be in the session."
assert session[:original_uri], 'Lost the redirect URL'
end
# Ensures that a user who logs in is sent to their dashboard.
- #
- def test_login_failure
- post :login, {:email => 'mcpierce(a)gmail.com',
- :password => 'farkle'}
+ def test_login
+ old_last_logged_in = User.find_by_email('mcpierce(a)gmail.com').last_logged_in
+
+ post :login,
+ {:email => 'mcpierce(a)gmail.com',:password => 'farkle'}
assert_redirected_to dashboard_url
+ assert User.find_by_email('mcpierce(a)gmail.com').last_logged_in > old_last_logged_in
end
# Ensures that the user's session is destroyed on logout.
- #
def test_logout
get :logout, nil, {:user_id => @authenticated_user.id}
@@ -84,7 +83,6 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that the main page doesn't require the user be logged.
- #
def test_index
get :index
--
1.6.0.2
15 years, 4 months
[PATCH] Added last logged in date to users table. #67
by Darryl L. Pierce
This patch requires that you do a migration.
Adds a new column to the users table for the user's last date and
time of login. Displays this value in the user list.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/home_controller.rb | 7 ++++-
app/helpers/application_helper.rb | 10 ++++---
app/views/users/_list.html.erb | 3 ++
db/migrate/023_add_last_logged_in_date_to_users.rb | 26 ++++++++++++++++++++
db/schema.rb | 4 ++-
test/fixtures/users.yml | 7 +++++
test/functional/home_controller_test.rb | 22 ++++++++--------
7 files changed, 61 insertions(+), 18 deletions(-)
create mode 100644 db/migrate/023_add_last_logged_in_date_to_users.rb
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 15d708c..2f9085d 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -40,11 +40,9 @@ class HomeController < ApplicationController
# dashboard.
#
# On failure, the user is reshown the login page.
- #
def login
session[:user_id] = nil
- # if the user was doing a login, then process the values submitted
if request.post?
user = User.authenticate(params[:email], params[:password])
@@ -52,6 +50,11 @@ class HomeController < ApplicationController
session[:user_id] = user.id
uri = session[:original_uri]
session[:original_uri] = nil
+ user.last_logged_in = DateTime.now
+
+ User.transaction do
+ user.save
+ end
redirect_to(uri || dashboard_url)
else
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 9e81b48..47e76bb 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -37,10 +37,12 @@ module ApplicationHelper
# Displays a date or date and time.
def show_date(datetime, include_time = false)
- if include_time
- datetime.strftime("%m/%d/%Y %I:%M:%S %P")
- else
- datetime.strftime("%m/%d/%Y")
+ if datetime
+ if include_time
+ datetime.strftime("%m/%d/%Y %I:%M:%S %P")
+ else
+ datetime.strftime("%m/%d/%Y")
+ end
end
end
diff --git a/app/views/users/_list.html.erb b/app/views/users/_list.html.erb
index d4bb89f..c36e77e 100644
--- a/app/views/users/_list.html.erb
+++ b/app/views/users/_list.html.erb
@@ -7,6 +7,7 @@
<col class="number" />
<col class="number" />
<col class="date" />
+ <col class="date" />
<col class="actions" />
</colgroup>
@@ -18,6 +19,7 @@
<th>Email</th>
<th>Backlog</th>
<th>Roles</th>
+ <th>Last On</th>
<th>Since</th>
<th>Actions</th>
</tr>
@@ -34,6 +36,7 @@
<td><%= mail_to user.email, user.display_name %></td>
<td><%= link_to "#{user.backlog.size} items", backlog_user_path(user) %>
<td><%= link_to "#{user.product_roles.size} roles", roles_user_path(user) %></td>
+ <td><%= show_date(user.last_logged_in) %></td>
<td><%= show_date(user.created_at) %></td>
<td>
<%= link_to(image_tag("icons/view.png", :alt => "View user..."), user_path(user)) %>
diff --git a/db/migrate/023_add_last_logged_in_date_to_users.rb b/db/migrate/023_add_last_logged_in_date_to_users.rb
new file mode 100644
index 0000000..824f7f5
--- /dev/null
+++ b/db/migrate/023_add_last_logged_in_date_to_users.rb
@@ -0,0 +1,26 @@
+# 023_add_last_logged_in_date_to_users.rb
+# Copyright (C) 2008, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+class AddLastLoggedInDateToUsers < ActiveRecord::Migration
+ def self.up
+ add_column :users, :last_logged_in, :datetime, :null => false
+ end
+
+ def self.down
+ remove_column :users, :last_logged_in
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6c86037..024b1cd 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 => 21) do
+ActiveRecord::Schema.define(:version => 23) do
create_table "backlog_items", :force => true do |t|
t.integer "sprint_id", :null => false
@@ -31,6 +31,7 @@ ActiveRecord::Schema.define(:version => 21) do
t.boolean "daily_updates"
t.datetime "created_at"
t.datetime "updated_at"
+ t.boolean "updates_to_product_list", :default => false
end
create_table "product_roles", :force => true do |t|
@@ -173,6 +174,7 @@ ActiveRecord::Schema.define(:version => 21) do
t.text "introduction"
t.datetime "created_at"
t.datetime "updated_at"
+ t.datetime "last_logged_in", :null => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index 6a204c8..dfefb66 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -6,6 +6,7 @@ admin:
introduction: Can't you see I'm busy?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('admin', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
projxp_owner:
email: admin(a)projxp.org
@@ -13,6 +14,7 @@ projxp_owner:
introduction: Wassup?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('bonk', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
teatime_owner:
email: admin(a)teatime.org
@@ -20,6 +22,7 @@ teatime_owner:
introduction: I'd like a nice cuppa.
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('earlgrey', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
mcpierce:
email: mcpierce(a)gmail.com
@@ -27,6 +30,7 @@ mcpierce:
introduction: How are you?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('farkle', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
jdonuts:
email: jdonuts(a)gmail.com
@@ -34,6 +38,7 @@ jdonuts:
introduction: How's it going, eh?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('jelly', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
celliot:
email: celliot(a)gmail.com
@@ -41,6 +46,7 @@ celliot:
introduction: Get a life.
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('loser', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
unverified_user:
email: unverified(a)newuser.com
@@ -48,3 +54,4 @@ unverified_user:
introduction: Am I who I say I am?
salt: <%= SALT %>
hashed_password: <%= User.encrypted_password('unverified', SALT) %>
+ last_logged_in: <%= DateTime.now - 1 %>
diff --git a/test/functional/home_controller_test.rb b/test/functional/home_controller_test.rb
index 94574b5..6edd68e 100644
--- a/test/functional/home_controller_test.rb
+++ b/test/functional/home_controller_test.rb
@@ -33,7 +33,6 @@ class HomeControllerTest < ActionController::TestCase
# Ensures that anonymous users are sent to the login page when they try to
# view the dashboard.
- #
def test_dashboard_for_anonymous_user
get :dashboard
@@ -42,7 +41,6 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that authenticated users are shown their dashboard.
- #
def test_dashboard_for_authenticated_user
get :dashboard, nil, {:user_id => @authenticated_user.id}
@@ -52,30 +50,33 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that a failed login redirects back to the login action.
- #
def test_login_failure
get :dashboard
- assert_redirected_to :action => :login
+ assert_redirected_to login_path
post :login, {:email => 'mcpierce(a)gmail.com',
:password => 'klefar' }
- assert_redirected_to :action => :login
+ assert_response :success
+ assert !session[:user_id], "User ID should not be in the session."
assert session[:original_uri], 'Lost the redirect URL'
end
# Ensures that a user who logs in is sent to their dashboard.
- #
- def test_login_failure
- post :login, {:email => 'mcpierce(a)gmail.com',
- :password => 'farkle'}
+ def test_login
+ old_last_logged_in = User.find_by_email('mcpierce(a)gmail.com').last_logged_in
+
+ post :login,
+ {:email => 'mcpierce(a)gmail.com',:password => 'farkle'}
+
+ puts "ERROR: #{flash[:error]}"
assert_redirected_to dashboard_url
+ assert User.find_by_email('mcpierce(a)gmail.com').last_logged_in > old_last_logged_in
end
# Ensures that the user's session is destroyed on logout.
- #
def test_logout
get :logout, nil, {:user_id => @authenticated_user.id}
@@ -84,7 +85,6 @@ class HomeControllerTest < ActionController::TestCase
end
# Ensures that the main page doesn't require the user be logged.
- #
def test_index
get :index
--
1.6.0.2
15 years, 4 months
[PATCH] If a sprint is active and has no tasks against it, then it can be moved back to the planned state. #71
by LAN-SUN-LUK Benjamin
Thanks for the suggestions.
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/controllers/sprints_controller.rb | 22 ++++++++++++++--------
app/models/sprint.rb | 10 ++++++++++
app/views/sprints/show.html.erb | 2 +-
3 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/app/controllers/sprints_controller.rb
b/app/controllers/sprints_controller.rb
index 09ebe5b..f8f5881 100644
--- a/app/controllers/sprints_controller.rb
+++ b/app/controllers/sprints_controller.rb
@@ -87,15 +87,21 @@ class SprintsController < ApplicationController
def update
respond_to do |format|
if @sprint.can_edit?(@user)
- @sprint.update_attributes(params[:sprint])
-
- if @sprint.save
- flash[:message] = "Sprint updated successfully."
- format.html { redirect_to params[:url] ? params[:url] :
product_sprints_path(@product) }
+ unless @sprint.allowed_status?(params[:sprint][:status] ||
@sprint.status)
+ flash[:error] = "You cannot change the status because you got
tasks against the sprint"
+ format.html { redirect_to :action => :show }
else
- @title = "Sprint #{(a)sprint.id} (Edit)"
- @sprint.valid?
- format.html { render :action => :edit }
+
+ @sprint.update_attributes(params[:sprint])
+
+ if @sprint.save
+ flash[:message] = "Sprint updated successfully."
+ format.html { redirect_to params[:url] ? params[:url] :
product_sprints_path(@product) }
+ else
+ @title = "Sprint #{(a)sprint.id} (Edit)"
+ @sprint.valid?
+ format.html { render :action => :edit }
+ end
end
else
flash[:error] = "You are now allowed to edit sprints for
#{(a)product.name}."
diff --git a/app/models/sprint.rb b/app/models/sprint.rb
index 2638613..da092ee 100644
--- a/app/models/sprint.rb
+++ b/app/models/sprint.rb
@@ -171,4 +171,14 @@ class Sprint < ActiveRecord::Base
return false
end
+
+ # Check if the sprint is active and have tasks againsts him.
+ def has_activity?
+ status == STATUS_ACTIVE && !actual_hours.zero?
+ end
+
+ # Check if the sprint can move to this new status
+ def allowed_status?(new_status)
+ !(has_activity? && new_status.to_i == STATUS_PLANNED)
+ end
end
diff --git a/app/views/sprints/show.html.erb
b/app/views/sprints/show.html.erb
index 6fb47e3..6db7c0e 100644
--- a/app/views/sprints/show.html.erb
+++ b/app/views/sprints/show.html.erb
@@ -46,7 +46,7 @@
<% form_for(:sprint, @sprint, :url =>
product_sprint_path(@product, @sprint),
:html => {:method => :put}) do |form| %>
<%= hidden_field_tag :url, product_sprint_url(@product,
@sprint) %>
- <%= select :sprint, :status, Sprint::STATUS_TEXT %>
+ <%= select :sprint, :status, @sprint.has_activity? ?
Sprint::STATUS_TEXT[1..3] : Sprint::STATUS_TEXT %>
<%= submit_tag "Apply" %>
<% end %>
<% else %>
--
1.6.0.2
15 years, 4 months
[PATCH] If a sprint is active and has no tasks against it, then it can be moved back to the planned state. #71
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/controllers/sprints_controller.rb | 26 ++++++++++++++++++--------
1 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/app/controllers/sprints_controller.rb
b/app/controllers/sprints_controller.rb
index 09ebe5b..29e2d49 100644
--- a/app/controllers/sprints_controller.rb
+++ b/app/controllers/sprints_controller.rb
@@ -87,15 +87,25 @@ class SprintsController < ApplicationController
def update
respond_to do |format|
if @sprint.can_edit?(@user)
- @sprint.update_attributes(params[:sprint])
-
- if @sprint.save
- flash[:message] = "Sprint updated successfully."
- format.html { redirect_to params[:url] ? params[:url] :
product_sprints_path(@product) }
+ if params[:sprint][:status].to_i == Sprint::STATUS_PLANNED
+ @sprint.backlog_items.each do |backlog_item|
+ unless backlog_item.tasks.empty?
+ flash[:error] = "You cannot change the status because you got
tasks against the sprint"
+ format.html { redirect_to :action => :show }
+ end
+ end
else
- @title = "Sprint #{(a)sprint.id} (Edit)"
- @sprint.valid?
- format.html { render :action => :edit }
+
+ @sprint.update_attributes(params[:sprint])
+
+ if @sprint.save
+ flash[:message] = "Sprint updated successfully."
+ format.html { redirect_to params[:url] ? params[:url] :
product_sprints_path(@product) }
+ else
+ @title = "Sprint #{(a)sprint.id} (Edit)"
+ @sprint.valid?
+ format.html { render :action => :edit }
+ end
end
else
flash[:error] = "You are now allowed to edit sprints for
#{(a)product.name}."
--
1.6.0.2
15 years, 4 months
[PATCH] A user cannot delete a backlog item from sprint if that item has tasks. #45
by LAN-SUN-LUK Benjamin
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/controllers/items_controller.rb | 1 +
app/models/backlog_item.rb | 2 +-
2 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/app/controllers/items_controller.rb
b/app/controllers/items_controller.rb
index fa68ad0..902daf8 100644
--- a/app/controllers/items_controller.rb
+++ b/app/controllers/items_controller.rb
@@ -100,6 +100,7 @@ class ItemsController < ApplicationController
# GET /products/1/sprints/1/items/1/drop
def drop
+ raise "You cannot drop that backlog item because some tasks are against
it." unless @backlog_item.tasks.empty?
respond_to do |format|
if @backlog_item.can_drop?(@user)
@backlog_item.drop
diff --git a/app/models/backlog_item.rb b/app/models/backlog_item.rb
index 4fd4501..d962fda 100644
--- a/app/models/backlog_item.rb
+++ b/app/models/backlog_item.rb
@@ -152,7 +152,7 @@ class BacklogItem < ActiveRecord::Base
# Returns whether the user can drop this backlog item.
def can_drop?(user)
- (state == STATE_ASSIGNED) && owner?(user) && sprint.active?
+ (state == STATE_ASSIGNED) && owner?(user) && sprint.active? &&
self.tasks.empty?
end
# Returns whether the user can complete this backlog item.
--
1.6.0.2
15 years, 4 months
[PATCH] A user cannot delete a backlog item from sprint if that item has tasks. #45
by LAN-SUN-LUK Benjamin
Ok. Now, if the item have some tasks, icon are not show and the controller
raise.
Signed-off-by: Benjamin LAN-SUN-LUK <benjamin.lan-sun-luk(a)supinfo.com>
---
app/models/backlog_item.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/app/models/backlog_item.rb b/app/models/backlog_item.rb
index 4fd4501..d962fda 100644
--- a/app/models/backlog_item.rb
+++ b/app/models/backlog_item.rb
@@ -152,7 +152,7 @@ class BacklogItem < ActiveRecord::Base
# Returns whether the user can drop this backlog item.
def can_drop?(user)
- (state == STATE_ASSIGNED) && owner?(user) && sprint.active?
+ (state == STATE_ASSIGNED) && owner?(user) && sprint.active? &&
self.tasks.empty?
end
# Returns whether the user can complete this backlog item.
--
1.6.0.2
15 years, 4 months