[PATCH] Epics can be viewed in detail. #155
by Darryl L. Pierce
Added unit tests for the EpicsController::show method. Created the show
html. Added commands to edit the epic, view all epics and return to the
proejct list, and also to delete an epic.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/epics_controller.rb | 4 +++-
app/views/epics/index.html.erb | 2 +-
app/views/epics/show.html.erb | 29 +++++++++++++++++++++++++++--
test/fixtures/epics.yml | 3 +++
test/functional/epics_controller_test.rb | 30 ++++++++++++++++++++++++++++++
5 files changed, 64 insertions(+), 4 deletions(-)
diff --git a/app/controllers/epics_controller.rb b/app/controllers/epics_controller.rb
index b51eb34..6f7f819 100644
--- a/app/controllers/epics_controller.rb
+++ b/app/controllers/epics_controller.rb
@@ -18,7 +18,7 @@
class EpicsController < ApplicationController
before_filter :authenticated, :only => [:new, :edit, :create, :update, :destroy]
before_filter :load_project
- before_filter :load_epic, :only => [:edit, :update, :destroy]
+ before_filter :load_epic, :only => [:show, :edit, :update, :destroy]
# GET /projects/1/epics
def index
@@ -32,7 +32,9 @@ class EpicsController < ApplicationController
end
end
+ # GET/projects/1/epics/1
def show
+ @title = "Epic:#{@epic.title}"
end
# GET /projects/1/epics/new
diff --git a/app/views/epics/index.html.erb b/app/views/epics/index.html.erb
index d1a1d35..dae7da9 100644
--- a/app/views/epics/index.html.erb
+++ b/app/views/epics/index.html.erb
@@ -21,7 +21,7 @@
<td><%= epic.priority %></td>
<td class="name">
<%= link_to "#{epic.title}", project_epic_path(@project, epic) %>
- <%= RedCloth.new(get_first_sentence epic.description).to_html %>
+ <%= RedCloth.new(get_first_sentence(epic.description)).to_html %>
</td>
<td><%= epic.user_stories.size %></td>
<td><%= show_date epic.created_at %></td>
diff --git a/app/views/epics/show.html.erb b/app/views/epics/show.html.erb
index a4b53c6..2c28250 100644
--- a/app/views/epics/show.html.erb
+++ b/app/views/epics/show.html.erb
@@ -1,2 +1,27 @@
-<h1>Epics#show</h1>
-<p>Find me in app/views/epics/show.html.erb</p>
+<div id="content">
+ <div id="page-details">
+ <dl>
+ <dt><%= "#{(a)epic.title} (Priority: #{(a)epic.priority})" %></dt>
+ <dd><%= RedCloth.new((a)epic.description).to_html %></dd>
+ </dl>
+ </div>
+</div>
+
+<div id="sidebar">
+ <%= link_to "View parent project",
+ project_path(@project), :class => "command" %>
+
+ <%= link_to "View all epics for this project",
+ project_epics_path(@project), :class => "command" %>
+
+ <% if @epic.can_edit?(@user) %>
+ <%= link_to "Edit this epic",
+ edit_project_epic_path(@project, @epic), :class => "command" %>
+ <% end %>
+
+ <% if @epic.can_delete?(@user) %>
+ <%= link_to "Delete this epic...",
+ project_epic_path(@project, @epic), :class => "command",
+ :confirm => "Delete this epic? Are you sure?", :method => :delete %>
+ <% end %>
+</div>
diff --git a/test/fixtures/epics.yml b/test/fixtures/epics.yml
index ee25170..3654b8d 100644
--- a/test/fixtures/epics.yml
+++ b/test/fixtures/epics.yml
@@ -2,13 +2,16 @@ user_stories_epic:
project_id: <%= Fixtures.identify(:projxp) %>
priority: 1
title: User stories capture individual features.
+ description: User stories.
login_epic:
project_id: <%= Fixtures.identify(:projxp) %>
priority: 2
title: Covers all login attempts.
+ description: Login stories.
no_user_story_epic:
project_id: <%= Fixtures.identify(:projxp) %>
priority: 3
title: Has no user stories.
+ description: Epic with no user stories.
diff --git a/test/functional/epics_controller_test.rb b/test/functional/epics_controller_test.rb
index 9ea00e3..5660f32 100644
--- a/test/functional/epics_controller_test.rb
+++ b/test/functional/epics_controller_test.rb
@@ -51,6 +51,36 @@ class EpicsControllerTest < ActionController::TestCase
assert assigns['project'], "Failed to load the project."
end
+ # Ensures that viewing an epic requires a valid project.
+ def test_show_with_invalid_project
+ get :show, { }
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that a valid epic id is required.
+ def test_show_with_invalid_epic
+ get :show, {:project_id => @project.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that the epic and project must match.
+ def test_show_with_project_epic_mismatch
+ get :show, {:project_id => @other_project.id, :id => @epic.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that showing an epic works as expected.
+ def test_show
+ get :show, {:project_id => @project.id, :id => @epic.id}
+
+ assert_response :success
+ assert assigns['epic'], "Failed to load the epic."
+ assert_equal @epic.id, assigns['epic'].id, "Loaded the wrong epic."
+ end
+
# Ensures that anonymous users cannot create new epics.
def test_new_as_anonymous
get :new
--
1.6.0.6
15 years
[PATCH] Moved the sidebar to be a partial template with rounded corners.
by Darryl L. Pierce
Applied the new sidebar layout to all pages.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/views/epics/index.html.erb | 4 +-
app/views/home/_sidebar.html.erb | 19 ++++++++++
app/views/items/index.html.erb | 4 +-
app/views/items/show.html.erb | 4 +-
app/views/products/index.html.erb | 5 +--
app/views/products/show.html.erb | 10 +----
app/views/projects/_edit.html.erb | 3 --
app/views/projects/index.html.erb | 4 +-
app/views/projects/show.html.erb | 15 ++-------
app/views/sprints/index.html.erb | 4 +-
app/views/sprints/show.html.erb | 17 +++++----
app/views/stories/index.html.erb | 4 +-
app/views/stories/show.html.erb | 4 +-
app/views/tasks/show.html.erb | 4 +-
app/views/users/index.html.erb | 3 --
app/views/users/show.html.erb | 4 +-
public/stylesheets/sidebar.css | 66 ++++++++++++++++++++++++++++++++++--
public/stylesheets/tables.css | 1 +
18 files changed, 116 insertions(+), 59 deletions(-)
create mode 100644 app/views/home/_sidebar.html.erb
diff --git a/app/views/epics/index.html.erb b/app/views/epics/index.html.erb
index d1a1d35..acda0cb 100644
--- a/app/views/epics/index.html.erb
+++ b/app/views/epics/index.html.erb
@@ -32,7 +32,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => "Commands"} do %>
<%= link_to "View parent project",
project_path(@project), :class => "command" %>
@@ -40,4 +40,4 @@
<%= link_to "Write new epic...",
new_project_epic_path(@project), :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/home/_sidebar.html.erb b/app/views/home/_sidebar.html.erb
new file mode 100644
index 0000000..78c5692
--- /dev/null
+++ b/app/views/home/_sidebar.html.erb
@@ -0,0 +1,19 @@
+<div id="sidebar">
+ <div id="interior">
+ <b class="b1h"></b>
+ <b class="b2h"></b>
+ <b class="b3h"></b>
+ <b class="b4h"></b>
+
+ <% if title %>
+ <div class="header"><span class="title"><%= title %></span></div>
+ <% end %>
+
+ <%= yield %>
+
+ <b class="b4bh"></b>
+ <b class="b3bh"></b>
+ <b class="b2bh"></b>
+ <b class="b1bh"></b>
+ </div>
+</div>
diff --git a/app/views/items/index.html.erb b/app/views/items/index.html.erb
index 3bc5fcd..033b14c 100644
--- a/app/views/items/index.html.erb
+++ b/app/views/items/index.html.erb
@@ -2,7 +2,7 @@
<%= render :partial => 'list', :locals => {:items => @backlog_items} %>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Commands'} do %>
<% if @sprint %>
<%= link_to "View sprint",
product_sprint_path(@product, @sprint), :class => "command" %>
@@ -12,4 +12,4 @@
plan_product_sprint_path(@product, @sprint), :class => "command" %>
<% end %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/items/show.html.erb b/app/views/items/show.html.erb
index c6c1263..9bc2fce 100644
--- a/app/views/items/show.html.erb
+++ b/app/views/items/show.html.erb
@@ -17,7 +17,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Backlog Item Commands'} do %>
<%= link_to "View sprint",
product_sprint_path(@product, @sprint), :class => "command" %>
@@ -50,4 +50,4 @@
reopen_product_sprint_item_path(@product, @sprint, @backlog_item,
:url => request.request_uri), :confirm => "Reopen this item? Are you sure?", :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/products/index.html.erb b/app/views/products/index.html.erb
index 222602e..9ed1404 100644
--- a/app/views/products/index.html.erb
+++ b/app/views/products/index.html.erb
@@ -48,7 +48,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => "Commands"} do %>
<% if @project %>
<%= link_to "View parent project",
project_path(@project), :class => "command" %>
@@ -58,5 +58,4 @@
<%= link_to "Add new product...",
new_product_path(:project => @project.id), :class => "command" %>
<% end %>
-</div>
-
+<% end %>
diff --git a/app/views/products/show.html.erb b/app/views/products/show.html.erb
index ce3b941..db89399 100644
--- a/app/views/products/show.html.erb
+++ b/app/views/products/show.html.erb
@@ -17,7 +17,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => "Product Commands"} do %>
<%= link_to "View parent project",
project_path((a)product.project), :class => "command" %>
@@ -31,10 +31,4 @@
<%= link_to "Sprints (#{(a)product.sprints.size} total)",
product_sprints_path(@product), :class => "command" %>
-
- <div>
- <dl>
- <dt>Reports</dt>
- </dl>
- </div>
-</div>
+<% end %>
diff --git a/app/views/projects/_edit.html.erb b/app/views/projects/_edit.html.erb
index 48a2062..3709a70 100644
--- a/app/views/projects/_edit.html.erb
+++ b/app/views/projects/_edit.html.erb
@@ -50,6 +50,3 @@
</table>
<% end %>
</div>
-
-<div class="sidebar">
-</div>
diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb
index 9df2d87..74781d2 100644
--- a/app/views/projects/index.html.erb
+++ b/app/views/projects/index.html.erb
@@ -37,8 +37,8 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Options'} do %>
<% if @user %>
<%= link_to "Request A New Project", new_project_path, :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb
index 9864ef2..440a1cc 100644
--- a/app/views/projects/show.html.erb
+++ b/app/views/projects/show.html.erb
@@ -23,8 +23,8 @@
</div>
</div>
-<div id="sidebar">
- <% if @project.can_edit?(@user) %>
+<% render :layout => 'home/sidebar', :locals => {:title => 'Project Commands'} do %>
+ <% if @project.can_edit?(@user) %>
<%= link_to "Edit this project",
edit_project_path(@project), :class => "command" %>
<% end %>
@@ -39,13 +39,4 @@
<%= link_to "Show all products (#{(a)project.products.size} total)",
products_path(:project => @project), :class => "command" %>
- <div>
- <dl>
- <dt>Reports</dt>
- <dd>
- <ul class="options">
- </ul>
- </dd>
- </dl>
- </div>
-</div>
+<% end %>
diff --git a/app/views/sprints/index.html.erb b/app/views/sprints/index.html.erb
index 5087c3f..7a00032 100644
--- a/app/views/sprints/index.html.erb
+++ b/app/views/sprints/index.html.erb
@@ -39,7 +39,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Commands'} do %>
<%= link_to "View parent product",
product_path(@product), :class => "command" %>
@@ -47,4 +47,4 @@
<%= link_to "Create sprint...",
new_product_sprint_path(@product), :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/sprints/show.html.erb b/app/views/sprints/show.html.erb
index 37f6d7c..38988b1 100644
--- a/app/views/sprints/show.html.erb
+++ b/app/views/sprints/show.html.erb
@@ -17,7 +17,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Sprint Commands'} do %>
<%= link_to "View parent product",
product_path(@product), :class => "command" %>
@@ -26,12 +26,19 @@
edit_product_sprint_path(@product, @sprint), :class => "command" %>
<% end %>
+ <%= link_to "View sprint members (#{(a)sprint.members.size} total members)...",
+ members_product_sprint_path(@product, @sprint), :class => "command" %>
+ <%= link_to "View sprint backlog (#{(a)sprint.backlog_items.size} total items)...",
+ product_sprint_items_path(@product, @sprint), :class => "command" %>
+
<% if @sprint.can_edit?(@user) %>
<% if @sprint.can_populate?(@user) %>
<%= link_to "Plan this sprint...",
plan_product_sprint_path(@product, @sprint), :class => "command" %>
<% end %>
+ <div class="header"><span class="title">Change Sprint Status</span></div>
+
<% if @sprint.allowed_status?(Sprint::STATUS_PLANNED) %>
<%= link_to "Move sprint back to planning...",
status_product_sprint_path(@product, @sprint, :status => Sprint::STATUS_PLANNED),
@@ -60,11 +67,5 @@
:class => "command" %>
<% end %>
-
<% end %>
-
- <%= link_to "View sprint members (#{(a)sprint.members.size} total members)...",
- members_product_sprint_path(@product, @sprint), :class => "command" %>
- <%= link_to "View sprint backlog (#{(a)sprint.backlog_items.size} total items)...",
- product_sprint_items_path(@product, @sprint), :class => "command" %>
-</div>
+<% end %>
diff --git a/app/views/stories/index.html.erb b/app/views/stories/index.html.erb
index 2c19a5a..af56881 100644
--- a/app/views/stories/index.html.erb
+++ b/app/views/stories/index.html.erb
@@ -39,7 +39,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Commands'} do %>
<%= link_to "Return to product page...",
product_path(@product), :class => "command" %>
@@ -47,4 +47,4 @@
<%= link_to "Write user stories...",
new_product_story_path(@product), :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/stories/show.html.erb b/app/views/stories/show.html.erb
index 9e707ea..c0b8013 100644
--- a/app/views/stories/show.html.erb
+++ b/app/views/stories/show.html.erb
@@ -7,7 +7,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'User Story Commands'} do %>
<%= link_to "Return to user stories list...",
product_stories_path(@product), :class => "command" %>
@@ -15,4 +15,4 @@
<%= link_to "Edit user story...",
edit_product_story_path(@product, @user_story), :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/tasks/show.html.erb b/app/views/tasks/show.html.erb
index 486d7a5..60d9ca4 100644
--- a/app/views/tasks/show.html.erb
+++ b/app/views/tasks/show.html.erb
@@ -13,7 +13,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'Task Commands'} do %>
<%= link_to "View backlog item",
product_sprint_item_path(@product, @sprint, @backlog_item), :class => "command" %>
@@ -27,4 +27,4 @@
user_task_path((a)task.primary, @task), :method => :delete,
:confirm => "Delete this task? Are you sure?", :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb
index 9440abe..e08b04c 100644
--- a/app/views/users/index.html.erb
+++ b/app/views/users/index.html.erb
@@ -28,6 +28,3 @@
</table>
</div>
-<div id="sidebar">
-</div>
-
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb
index 3c75f53..6762daa 100644
--- a/app/views/users/show.html.erb
+++ b/app/views/users/show.html.erb
@@ -25,7 +25,7 @@
</div>
</div>
-<div id="sidebar">
+<% render :layout => 'home/sidebar', :locals => {:title => 'User Commands'} do %>
<% if @this_user.can_edit?(@user) %>
<%= link_to "Edit #{(a)this_user.id == @user.id ? 'your details' : 'this user'}",
edit_user_path(@this_user), :class => "command" %>
@@ -35,4 +35,4 @@
<%= link_to "Change password",
password_user_path(@this_user), :class => "command" %>
<% end %>
-</div>
+<% end %>
diff --git a/public/stylesheets/sidebar.css b/public/stylesheets/sidebar.css
index e5e0444..592dc65 100644
--- a/public/stylesheets/sidebar.css
+++ b/public/stylesheets/sidebar.css
@@ -1,16 +1,74 @@
+/* rounded corners */
+
+div#sidebar #interior {
+ padding: 5px;
+}
+
+.b1h, .b2h, .b3h, .b4h, .b2bh, .b3bh, .b4bh {
+ font-size:1px;
+ overflow:hidden;
+ display:block;
+}
+
+.b1h {
+ height:1px;
+ background:#f00;
+ margin:0 5px;
+}
+
+.b2h, .b2bh {
+ height:1px;
+ background:#f00;
+ border-right:2px solid #f00;
+ border-left:2px solid #f00;
+ margin:0 3px;
+}
+
+.b3h, .b3bh {
+ height:1px;
+ background:#f00;
+ border-right:1px solid #f00;
+ border-left:1px solid #f00;
+ margin:0 2px;
+}
+
+.b4h, .b4bh {
+ height:2px;
+ background:#f00;
+ border-right:1px solid #f00;
+ border-left:1px solid #f00;
+ margin:0 1px;
+}
+
+.b2bh, .b3bh, .b4bh {
+ background: #f00;
+}
+
+div#sidebar .header {
+ background: #f00;
+ border-right:1px solid #f00;
+ border-left:1px solid #f00;
+}
+
+div#sidebar .header span.title {
+ color: #ff0;
+ margin: 0px 10px 0px 10px;
+ padding-bottom: 3px;
+ font-weight: bold;
+ text-align: center;
+ text-transform: uppercase;
+}
+
div#sidebar a.command {
text-align: left;
text-indent: 25px;
text-decoration: none;
- width: 90%;
- margin-left: 5%;
+ width: 100%;
display: block;
padding: 2px 0px 3px 0px;
background: #f00;
color: #fff;
font-weight: bold;
- border-bottom: 1px solid #000;
- border-right: 1px solid #000;
}
div#sidebar a.command:hover {
diff --git a/public/stylesheets/tables.css b/public/stylesheets/tables.css
index 784cfb0..839a827 100644
--- a/public/stylesheets/tables.css
+++ b/public/stylesheets/tables.css
@@ -122,3 +122,4 @@ table.edit td.value {
padding-right: 15px;
text-align: left;
}
+
--
1.6.2
15 years
Overall look and feel change...
by Darryl L. Pierce
This patch provides an overall look and feel change for the application.
It should be complete, so please apply and test it and give me feedback
or an ACK.
15 years
Re: [PROJXP] [ProjXP] #114: If a user doesn't have avatar, then a default avatar is used.
by Darryl L. Pierce
On Mon, Apr 13, 2009 at 6:25 PM, ProjXP <trac(a)fedorahosted.org> wrote:
> #114: If a user doesn't have avatar, then a default avatar is used.
> --------------------------+-------------------------------------------------
> Reporter: mcpierce | Owner: nebj
> Type: enhancement | Status: closed
> Priority: major | Milestone: Version 0.2.0
> Component: Users | Version:
> Resolution: fixed | Keywords:
> --------------------------+-------------------------------------------------
> Changes (by nebj):
>
> * status: assigned => closed
> * resolution: => fixed
Before committing, did you apply the feedback I provided; i.e., adding
a migration to insert the default URL property into config_properties?
---8<[quote]---
I like the idea of making the default avatar configurable. However, if
we do this, there should be a migration added as well to inject the
default value. That way an admin can use the system out of the box
without having to manually inject a record.
---8<[quote]---
Otherwise, how will a system know what the default icon is to be?
--
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
More changes to the new layout ideas...
by Darryl L. Pierce
I added some changes to the sidebar to give a set of command options a
separate look, and to break out special things like links to RSS feeds,
space for helper texts, etc.
15 years
[PATCH] Project owners can edit epic stories. #148
by Darryl L. Pierce
Added tests to enforce business rules for editing an epic story.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/epics_controller.rb | 50 +++++++++++++-
app/views/epics/index.html.erb | 7 ++-
doc/ChangeLog | 1 +
test/functional/epics_controller_test.rb | 111 ++++++++++++++++++++++++++++++
4 files changed, 165 insertions(+), 4 deletions(-)
diff --git a/app/controllers/epics_controller.rb b/app/controllers/epics_controller.rb
index 1c662ea..55aadcb 100644
--- a/app/controllers/epics_controller.rb
+++ b/app/controllers/epics_controller.rb
@@ -16,8 +16,9 @@
# +EpicsController+ allows users to work with +Epic+ stories.
class EpicsController < ApplicationController
- before_filter :authenticated, :only => [:new, :create]
- before_filter :load_project, :only => [:index, :new, :create]
+ before_filter :authenticated, :only => [:new, :edit, :create, :update]
+ before_filter :load_project
+ before_filter :load_epic, :only => [:edit, :update]
# GET /projects/1/epics
def index
@@ -45,10 +46,17 @@ class EpicsController < ApplicationController
end
end
+ # GET /projects/1/epics/1/edit
def edit
+ if @project.can_edit_epics?(@user)
+ @title = "Edit epic for #{(a)project.name}"
+ else
+ flash[:error] = "You are not authorized to edit epics for this project."
+ redirect_to project_path(@project)
+ end
end
- # POST /proces/1/epics
+ # POST /projects/1/epics
def create
respond_to do |format|
if @project.can_edit_epics?(@user)
@@ -70,7 +78,26 @@ class EpicsController < ApplicationController
end
end
+ # PUT /projects/1/epics/1
def update
+ respond_to do |format|
+ if @project.can_edit_epics?(@user)
+ Epic.transaction do
+ @epic.update_attributes(params[:epic])
+ if @epic.save
+ flash[:message] = "Epic was updated."
+ format.html { redirect_to project_epic_path(@project, @epic) }
+ else
+ @title = "Edit epic for #{(a)project.name}"
+ @epic.valid?
+ format.html { render :action => :edit }
+ end
+ end
+ else
+ flash[:message] = "You are not authorized to update epics for this project."
+ format.html { redirect_to project_epic_path(@project, @epic) }
+ end
+ end
end
def destroy
@@ -87,4 +114,21 @@ class EpicsController < ApplicationController
end
end
end
+
+ def load_epic
+ @epic = Epic.find_by_id(params[:id])
+ if @epic
+ unless @epic.project_id == @project.id
+ respond_to do |format|
+ flash[:error] = "The epic requested does not belong to the project specified."
+ format.html { redirect_to error_path }
+ end
+ end
+ else
+ respond_to do |format|
+ format[:error] = "Invalid or missing epic id."
+ format.html { redirect_to error_path }
+ end
+ end
+ end
end
diff --git a/app/views/epics/index.html.erb b/app/views/epics/index.html.erb
index 5baf843..9ff7974 100644
--- a/app/views/epics/index.html.erb
+++ b/app/views/epics/index.html.erb
@@ -28,7 +28,12 @@
<td><%= epic.title %></td>
<td><%= epic.user_stories.size %></td>
<td><%= show_date epic.created_at, true %></td>
- <td></td>
+ <td>
+ <% if @project.can_edit_epics?(@user) %>
+ <%= link_to(image_tag("/images/icons/edit.png", :title => "Edit this epic story..."),
+ edit_project_epic_path(@project, epic)) %>
+ <% end %>
+ </td>
</tr>
<% end %>
</tbody>
diff --git a/doc/ChangeLog b/doc/ChangeLog
index d22f359..640ee02 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -25,5 +25,6 @@ Change Log (0.2.0):
* #142 - The product owner can populate the sprint team.
* #143 - Only sprint team members can accept sprint items.
* #147 - Project owners can write new epic stories.
+ * #148 - Project owners can edit epics stories.
* #152 - Users can view all epic stories for a project.
diff --git a/test/functional/epics_controller_test.rb b/test/functional/epics_controller_test.rb
index 1df9485..c095704 100644
--- a/test/functional/epics_controller_test.rb
+++ b/test/functional/epics_controller_test.rb
@@ -24,6 +24,11 @@ class EpicsControllerTest < ActionController::TestCase
def setup
@project = projects(:projxp)
@owner = @project.owner
+ @epic = epics(:user_stories_epic)
+ raise "Epic is not in this project!" unless @epic.project_id == @project.id
+
+ @other_project = projects(:teatime)
+ @other_owner = @other_project.owner
@nonowner = users(:mcpierce)
raise "Nonowner and owner cannot be the same user!" if @owner.id == @nonowner.id
@@ -112,4 +117,110 @@ class EpicsControllerTest < ActionController::TestCase
assert result, "The new epic was not saved."
assert_redirected_to project_epic_path(@project, result)
end
+
+ # Ensures that anonymous users cannot edit epics.
+ def test_edit_as_anonymous
+ get :edit
+
+ assert_redirected_to login_path
+ end
+
+ # Ensures that a valid project is required.
+ def test_edit_with_invalid_project
+ get :edit, { }, {:user_id => @owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that a valid epic id is required.
+ def test_edit_with_invalid_epic
+ get :edit, {:project_id => @project.id}, {:user_id => @owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that the epic and project must be a match.
+ def test_edit_with_epic_project_mismatch
+ get :edit, {:id => @epic.id, :project_id => @other_project.id}, {:user_id => @other_owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that a non-owner cannot edit an epic.
+ def test_edit_as_nonowner
+ get :edit, {:id => @epic.id, :project_id => @project.id}, {:user_id => @nonowner.id}
+
+ assert_redirected_to project_path(@project)
+ end
+
+ # Ensures that editing loads the epic story correctly.
+ def test_edit
+ get :edit, {:id => @epic.id, :project_id => @project.id}, {:user_id => @owner.id}
+
+ assert_response :success
+ assert assigns['epic'], "Failed to load the epic."
+ assert_equal @epic.id, assigns['epic'].id, "Failed to load the correct epic."
+ end
+
+ # Ensures that anonymous users cannot update epics.
+ def test_update_as_anonymous
+ put :update
+
+ assert_redirected_to login_path
+ end
+
+ # Ensures that a valid project is required.
+ def test_update_with_invalid_project
+ put :update, { }, {:user_id => @owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that a valid epic id is required.
+ def test_update_with_invalid_epic
+ put :update, {:project_id => @project.id}, {:user_id => @owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that the epic belongs to the specified project.
+ def test_update_with_epic_project_mismatch
+ put :update, {:project_id => @other_project.id, :id => @epic.id}, {:user_id => @other_owner.id}
+
+ assert_redirected_to error_path
+ end
+
+ # Ensures that only the project owner can update an epic.
+ def test_update_as_nonowner
+ put :update,
+ {:project_id => @project.id, :id => @epic.id, :epic => {:title => "test"}},
+ {:user_id => @nonowner.id}
+
+ assert_redirected_to project_epic_path(@project, @epic)
+ result = Epic.find_by_id((a)epic.id)
+ assert_equal @epic.title, result.title, "Epic should not have been updated."
+ end
+
+ # Ensures that a malformed epic sends the user back to the edit page.
+ def test_update_with_invalid_epic
+ put :update,
+ {:project_id => @project.id,:id => @epic.id, :epic => {:title => ''}},
+ {:user_id => @owner.id}
+
+ assert_response :success
+ assert_template "edit"
+ result = Epic.find_by_id((a)epic.id)
+ assert_equal @epic.title, result.title, "Epic should not have been updated."
+ end
+
+ # Ensures that epics are updated as expected.
+ def test_update
+ put :update,
+ {:project_id => @project.id, :id => @epic.id, :epic => {:title => "test"}},
+ {:user_id => @owner.id}
+
+ assert_redirected_to project_epic_path(@project, @epic)
+ result = Epic.find_by_id((a)epic.id)
+ assert_equal "test", result.title, "Epic was not updated as expected."
+ end
end
--
1.6.0.6
15 years
[PATCH] Epics are listed under projects. #152
by Darryl L. Pierce
Added a new controller for working with epic stories. Also added new
routing for epics to RESTfully place them below projects.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/epics_controller.rb | 62 ++++++++++++++++++++++++++++++
app/helpers/epics_helper.rb | 2 +
app/models/epic.rb | 2 +
app/views/epics/create.html.erb | 2 +
app/views/epics/destroy.html.erb | 2 +
app/views/epics/edit.html.erb | 2 +
app/views/epics/index.html.erb | 25 ++++++++++++
app/views/epics/new.html.erb | 2 +
app/views/epics/show.html.erb | 2 +
app/views/epics/update.html.erb | 2 +
config/routes.rb | 3 +
test/functional/epics_controller_test.rb | 41 ++++++++++++++++++++
12 files changed, 147 insertions(+), 0 deletions(-)
create mode 100644 app/controllers/epics_controller.rb
create mode 100644 app/helpers/epics_helper.rb
create mode 100644 app/views/epics/create.html.erb
create mode 100644 app/views/epics/destroy.html.erb
create mode 100644 app/views/epics/edit.html.erb
create mode 100644 app/views/epics/index.html.erb
create mode 100644 app/views/epics/new.html.erb
create mode 100644 app/views/epics/show.html.erb
create mode 100644 app/views/epics/update.html.erb
create mode 100644 test/functional/epics_controller_test.rb
diff --git a/app/controllers/epics_controller.rb b/app/controllers/epics_controller.rb
new file mode 100644
index 0000000..d58a507
--- /dev/null
+++ b/app/controllers/epics_controller.rb
@@ -0,0 +1,62 @@
+# stories_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/>.
+
+# +EpicsController+ allows users to work with +Epic+ stories.
+class EpicsController < ApplicationController
+ before_filter :load_project, :only => [:index]
+
+ # GET /projects/1/epics
+ def index
+ @title = "Epic stories for #{(a)project.name}"
+ @epics = Epic.paginate(:page => params[:page],
+ :per_page => 10,
+ :conditions => ["project_id = ?", @project.id],
+ :order => "priority")
+ respond_to do |format|
+ format.html
+ end
+ end
+
+ def show
+ end
+
+ def new
+ end
+
+ def edit
+ end
+
+ def create
+ end
+
+ def update
+ end
+
+ def destroy
+ end
+
+ private
+
+ def load_project
+ @project = Project.find_by_id(params[:project_id])
+ unless @project
+ flash[:message] = "Missing or invalid project id."
+ respond_to do |format|
+ format.html { redirect_to projects_path}
+ end
+ end
+ end
+end
diff --git a/app/helpers/epics_helper.rb b/app/helpers/epics_helper.rb
new file mode 100644
index 0000000..18d9ee1
--- /dev/null
+++ b/app/helpers/epics_helper.rb
@@ -0,0 +1,2 @@
+module EpicsHelper
+end
diff --git a/app/models/epic.rb b/app/models/epic.rb
index b86e7f7..e0224d6 100644
--- a/app/models/epic.rb
+++ b/app/models/epic.rb
@@ -32,6 +32,8 @@ class Epic < ActiveRecord::Base
validates_presence_of :title
+ has_many :user_stories
+
# Returns a title that's geared for selection lists.
def selectable_title
"#{title} (#{priority})"
diff --git a/app/views/epics/create.html.erb b/app/views/epics/create.html.erb
new file mode 100644
index 0000000..e43f678
--- /dev/null
+++ b/app/views/epics/create.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#create</h1>
+<p>Find me in app/views/epics/create.html.erb</p>
diff --git a/app/views/epics/destroy.html.erb b/app/views/epics/destroy.html.erb
new file mode 100644
index 0000000..1cf72ac
--- /dev/null
+++ b/app/views/epics/destroy.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#destroy</h1>
+<p>Find me in app/views/epics/destroy.html.erb</p>
diff --git a/app/views/epics/edit.html.erb b/app/views/epics/edit.html.erb
new file mode 100644
index 0000000..9a0cd29
--- /dev/null
+++ b/app/views/epics/edit.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#edit</h1>
+<p>Find me in app/views/epics/edit.html.erb</p>
diff --git a/app/views/epics/index.html.erb b/app/views/epics/index.html.erb
new file mode 100644
index 0000000..16acf86
--- /dev/null
+++ b/app/views/epics/index.html.erb
@@ -0,0 +1,25 @@
+<%= will_paginate @epics %>
+
+<table class="main-list">
+ <caption><%= "Epic Stories For #{(a)project.name}" %></caption>
+ <thead>
+ <tr>
+ <th scope="col">#</th>
+ <th scope="col">Rank</th>
+ <th scope="col" class="name">Title</th>
+ <th scope="col">User Stories</th>
+ <th scope="col">Created</th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @epics.each do |epic| %>
+ <tr class="<%= cycle('odd', 'even') %>">
+ <td><%= epic.id %></td>
+ <td><%= epic.priority %></td>
+ <td><%= epic.title %></td>
+ <td><%= epic.user_stories.size %></td>
+ <td><%= show_date epic.created_at, true %></td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
diff --git a/app/views/epics/new.html.erb b/app/views/epics/new.html.erb
new file mode 100644
index 0000000..b26bfe2
--- /dev/null
+++ b/app/views/epics/new.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#new</h1>
+<p>Find me in app/views/epics/new.html.erb</p>
diff --git a/app/views/epics/show.html.erb b/app/views/epics/show.html.erb
new file mode 100644
index 0000000..a4b53c6
--- /dev/null
+++ b/app/views/epics/show.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#show</h1>
+<p>Find me in app/views/epics/show.html.erb</p>
diff --git a/app/views/epics/update.html.erb b/app/views/epics/update.html.erb
new file mode 100644
index 0000000..9dac74b
--- /dev/null
+++ b/app/views/epics/update.html.erb
@@ -0,0 +1,2 @@
+<h1>Epics#update</h1>
+<p>Find me in app/views/epics/update.html.erb</p>
diff --git a/config/routes.rb b/config/routes.rb
index aa2b8fc..5f14233 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -21,6 +21,9 @@ ActionController::Routing::Routes.draw do |map|
admin.resource :server, :controller => 'ServerSettings'
end
+ map.resources :projects do |project|
+ project.resources :epics
+ end
map.resources :projects, :member =>
{
:approve => :put,
diff --git a/test/functional/epics_controller_test.rb b/test/functional/epics_controller_test.rb
new file mode 100644
index 0000000..1119238
--- /dev/null
+++ b/test/functional/epics_controller_test.rb
@@ -0,0 +1,41 @@
+# stories_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 EpicsControllerTest < ActionController::TestCase
+ fixtures :projects
+
+ def setup
+ @project = projects(:projxp)
+ end
+
+ # Ensures that viewing a list of epics requires a valid project.
+ def test_index_with_invalid_project
+ get :index, {:project => 9999}
+
+ assert_redirected_to projects_path
+ end
+
+ # Ensures that viewing a list of epics works as expected.
+ def test_index
+ get :index, {:project_id => @project.id}
+
+ assert_response :success
+ assert assigns['project'], "Failed to load the project."
+ end
+end
--
1.6.0.6
15 years
[PATCH] User stories can be related to epic stories. #104
by Darryl L. Pierce
THIS PATCH WILL REQUIRE A MIGRATION.
The user_stories table has a column, epic_id, that relates the user
story back to an epic story.
When creating or editing a user story, the user can select from a
dropdown of the list of all epics for that project that are not marked
as closed.
On the user stories list, the epic is shown for each user story
displayed, with a link back to view the epic.
Signed-off-by: Darryl L. Pierce <mcpierce(a)gmail.com>
---
app/controllers/stories_controller.rb | 11 ++++++++-
app/models/epic.rb | 5 ++++
app/models/user_story.rb | 1 +
app/views/stories/_edit.html.erb | 8 +++++++
app/views/stories/_list.html.erb | 11 ++++++---
db/migrate/031_add_epic_id_to_user_stories.rb | 29 +++++++++++++++++++++++++
test/fixtures/epics.yml | 7 +++++-
test/fixtures/user_stories.yml | 4 +++
test/functional/stories_controller_test.rb | 2 +
9 files changed, 72 insertions(+), 6 deletions(-)
create mode 100644 db/migrate/031_add_epic_id_to_user_stories.rb
diff --git a/app/controllers/stories_controller.rb b/app/controllers/stories_controller.rb
index 7cfd233..f18d490 100644
--- a/app/controllers/stories_controller.rb
+++ b/app/controllers/stories_controller.rb
@@ -47,6 +47,7 @@ class StoriesController < ApplicationController
@title = "User Story (New)"
@user_story = UserStory.new(:product_id => @product.id)
@source = params[:source]
+ load_epics
else
flash[:error] = "You are not allowed to write user stories for #{(a)product.name}."
redirect_to params[:source] ? params[:source] : product_path(@product)
@@ -57,6 +58,7 @@ class StoriesController < ApplicationController
def edit
if @user_story.can_edit?(@user)
@title = "User Story - #{(a)user_story.title} (Edit)"
+ load_epics
unless @product.id == @user_story.product_id
flash[:error] = "This user story does not belong to that product."
redirect_to params[:source] ? params[:source] : product_stories_path(@product)
@@ -81,7 +83,7 @@ class StoriesController < ApplicationController
if params[:add_another]
format.html {
- redirect_to params[:source] ?
+ redirect_to params[:source] ?
new_product_story_url(@product, :source => params[:source]) :
new_product_story_path(@product)
}
@@ -91,6 +93,7 @@ class StoriesController < ApplicationController
else
@title = "User Story (New)"
@user_story.valid?
+ load_epics
format.html { render :action => :edit }
end
end
@@ -114,6 +117,7 @@ class StoriesController < ApplicationController
else
@title = "User Story - #{(a)user_story.title} (Edit)"
@user_story.valid?
+ load_epics
format.html { render :action => :edit }
end
end
@@ -146,6 +150,7 @@ class StoriesController < ApplicationController
def load_product
@product = Product.find_by_id(params[:product_id])
+ @project = @product.project if @product
unless @product
flash[:error] = "Missing or invalid product."
@@ -174,4 +179,8 @@ class StoriesController < ApplicationController
end
end
end
+
+ def load_epics
+ @epics = Epic.find_all_by_project_id((a)project.id, :order => 'priority', :conditions => "closed = false")
+ end
end
diff --git a/app/models/epic.rb b/app/models/epic.rb
index 6763cae..b86e7f7 100644
--- a/app/models/epic.rb
+++ b/app/models/epic.rb
@@ -31,4 +31,9 @@ class Epic < ActiveRecord::Base
:greater_than => 0
validates_presence_of :title
+
+ # Returns a title that's geared for selection lists.
+ def selectable_title
+ "#{title} (#{priority})"
+ end
end
diff --git a/app/models/user_story.rb b/app/models/user_story.rb
index ba6c648..81a1675 100644
--- a/app/models/user_story.rb
+++ b/app/models/user_story.rb
@@ -35,6 +35,7 @@ class UserStory < ActiveRecord::Base
:minimum => 1
belongs_to :product
+ belongs_to :epic
has_many :backlog_items
# Returns whether the user can edit this user story.
diff --git a/app/views/stories/_edit.html.erb b/app/views/stories/_edit.html.erb
index cc290ce..22e606c 100644
--- a/app/views/stories/_edit.html.erb
+++ b/app/views/stories/_edit.html.erb
@@ -38,6 +38,14 @@
</td>
</tr>
+ <tr>
+ <td class="label">Epic Story</td>
+ <td class="value">
+ <%= collection_select :user_story, :epic_id, @epics, :id,
+ :selectable_title, {:include_blank => true} %>
+ </td>
+ </tr>
+
<tr>
<td class="label-required">Priority</td>
<td class="value">
diff --git a/app/views/stories/_list.html.erb b/app/views/stories/_list.html.erb
index 7ccd44b..bf9a3ad 100644
--- a/app/views/stories/_list.html.erb
+++ b/app/views/stories/_list.html.erb
@@ -1,8 +1,9 @@
<table class="list">
<colgroup>
<col class="row_id" />
- <col class="priority" />
+ <col class="number" />
<col class="description" />
+ <col class="number" />
<col class="actions" />
</colgroup>
@@ -12,8 +13,9 @@
</tr>
<tr>
<th>#</th>
- <th>!</th>
+ <th>Rank</th>
<th>Title</th>
+ <th>Epic</th>
<th>Actions</th>
</tr>
</thead>
@@ -21,16 +23,17 @@
<tbody>
<% if @user_stories.empty? %>
<tr>
- <td colspan="4">No user stories found...</td>
+ <td colspan="5">No user stories found...</td>
</tr>
<% else %>
<% @user_stories.each_with_index do |story, index| %>
<% row_class = index%2 == 0 ? 'even' : 'odd' %>
<tr class="<%= row_class %>">
- <td><%= "#{story.id}" %></td>
+ <td><%= story.id %></td>
<td><%= story.priority %></td>
<td><%= story.title %></td>
+ <td><%= story.epic.id %></td>
<td>
<%= link_to(image_tag("icons/view.png", :title => "View this user story..."),
product_story_path(story.product,story)) %>
diff --git a/db/migrate/031_add_epic_id_to_user_stories.rb b/db/migrate/031_add_epic_id_to_user_stories.rb
new file mode 100644
index 0000000..6e80f82
--- /dev/null
+++ b/db/migrate/031_add_epic_id_to_user_stories.rb
@@ -0,0 +1,29 @@
+# 031_add_epic_id_to_user_stories.rb
+# Copyright (C) 2009, Darryl L. Pierce <mcpierce(a)gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+class AddEpicIdToUserStories < ActiveRecord::Migration
+ def self.up
+ add_column :user_stories, :epic_id, :integer, :null => true
+
+ execute 'alter table user_stories add constraint fk_user_story_epic_id
+ foreign key (epic_id) references epics(id)'
+ end
+
+ def self.down
+ remove_column :user_stories, :epic_id
+ end
+end
diff --git a/test/fixtures/epics.yml b/test/fixtures/epics.yml
index 492bf61..664454c 100644
--- a/test/fixtures/epics.yml
+++ b/test/fixtures/epics.yml
@@ -1,4 +1,9 @@
-user_stories:
+user_stories_epic:
project_id: <%= Fixtures.identify(:projxp) %>
priority: 1
title: User stories capture individual features.
+
+login_epic:
+ project_id: <%= Fixtures.identify(:projxp) %>
+ priority: 2
+ title: Covers all login attempts.
diff --git a/test/fixtures/user_stories.yml b/test/fixtures/user_stories.yml
index 50e29e0..7f97e71 100644
--- a/test/fixtures/user_stories.yml
+++ b/test/fixtures/user_stories.yml
@@ -4,6 +4,7 @@ create_user_story:
title: Create the user story subsystem.
description: Create the data model and relationships for user stories.
closed: true
+ epic: <%= Fixtures.identify(:user_story_epic) %>
create_user_story_web_service_api:
product_id: <%= Fixtures.identify(:projxp_web_services) %>
@@ -11,6 +12,7 @@ create_user_story_web_service_api:
title: Create web services for the user story system.
description: Create a wrapper.
closed: false
+ epic: <%= Fixtures.identify(:user_story_epic) %>
create_login:
product_id: <%= Fixtures.identify(:projxp_web) %>
@@ -18,6 +20,7 @@ create_login:
title: Enable users to log into the system.
description: Create a user model, login controller and required pages.
closed: false
+ epic: <%= Fixtures.identify(:login_epic) %>
create_logout:
product_id: <%= Fixtures.identify(:projxp_web) %>
@@ -25,6 +28,7 @@ create_logout:
title: Users can log out of the system.
description: stuff.
closed: true
+ epic: <%= Fixtures.identify(:login_epic) %>
create_update_profile:
product_id: <%= Fixtures.identify(:projxp_web) %>
diff --git a/test/functional/stories_controller_test.rb b/test/functional/stories_controller_test.rb
index e0b4c32..fe5d42e 100644
--- a/test/functional/stories_controller_test.rb
+++ b/test/functional/stories_controller_test.rb
@@ -113,6 +113,7 @@ class StoriesControllerTest < ActionController::TestCase
assert_response :success
assert assigns['user_story'], "Failed to create a new user story."
+ assert assigns['epics'], "Failed to load any epic stories for this project."
end
# Ensures that anonymous users can't edit a user story.
@@ -165,6 +166,7 @@ class StoriesControllerTest < ActionController::TestCase
assert_response :success
assert assigns['user_story'], "Failed to load a user story to edit."
+ assert assigns['epics'], "Failed to load the set of epics."
assert_equal @existing_story.id, assigns['user_story'].id,
"Failed to load the correct user story."
end
--
1.6.0.6
15 years