NOTE: This patch fixes the bug found when viewing a product.
Added a new resource named :projects.
Renamed ProjectController and ProjectControllerTest to ProjectsController and ProjectsControllerTest, respectively.
Rewrote the functional tests to make sure they properly vetted the refactored controller.
Signed-off-by: Darryl L. Pierce mcpierce@gmail.com --- app/controllers/application.rb | 2 +- app/controllers/product_controller.rb | 2 +- app/controllers/project_controller.rb | 102 ------------ app/controllers/projects_controller.rb | 142 ++++++++++++++++ app/helpers/application_helper.rb | 57 +++---- app/models/project.rb | 13 ++- app/views/layouts/default.html.erb | 2 +- app/views/product/_details.html.erb | 2 +- app/views/project/_details.html.erb | 25 --- app/views/project/_edit.html.erb | 59 ------- app/views/project/_product.html.erb | 19 --- app/views/project/create.html.erb | 1 - app/views/project/index.html.erb | 48 ------ app/views/project/modify.html.erb | 1 - app/views/project/view.html.erb | 59 ------- app/views/projects/_details.html.erb | 25 +++ app/views/projects/_edit.html.erb | 58 +++++++ app/views/projects/_product.html.erb | 19 +++ app/views/projects/edit.html.erb | 1 + app/views/projects/index.html.erb | 56 +++++++ app/views/projects/new.html.erb | 1 + app/views/projects/show.html.erb | 59 +++++++ app/views/projects/update.html.erb | 1 + app/views/tasks/new.html.erb | 4 +- config/routes.rb | 3 +- test/functional/product_controller_test.rb | 4 +- test/functional/project_controller_test.rb | 176 -------------------- test/functional/projects_controller_test.rb | 233 +++++++++++++++++++++++++++ 28 files changed, 640 insertions(+), 534 deletions(-) delete mode 100644 app/controllers/project_controller.rb create mode 100644 app/controllers/projects_controller.rb delete mode 100644 app/views/project/_details.html.erb delete mode 100644 app/views/project/_edit.html.erb delete mode 100644 app/views/project/_product.html.erb delete mode 100644 app/views/project/create.html.erb delete mode 100644 app/views/project/index.html.erb delete mode 100644 app/views/project/modify.html.erb delete mode 100644 app/views/project/view.html.erb create mode 100644 app/views/projects/_details.html.erb create mode 100644 app/views/projects/_edit.html.erb create mode 100644 app/views/projects/_product.html.erb create mode 100644 app/views/projects/edit.html.erb create mode 100644 app/views/projects/index.html.erb create mode 100644 app/views/projects/new.html.erb create mode 100644 app/views/projects/show.html.erb create mode 100644 app/views/projects/update.html.erb delete mode 100644 test/functional/project_controller_test.rb create mode 100644 test/functional/projects_controller_test.rb
diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 3378a90..51261a0 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -34,7 +34,7 @@ class ApplicationController < ActionController::Base if @user == nil session[:original_uri] = request.request_uri flash[:message] = 'Please login first.' - redirect_to(:controller => :home, :action => :login) + redirect_to login_url end end
diff --git a/app/controllers/product_controller.rb b/app/controllers/product_controller.rb index f5553d3..43c6425 100644 --- a/app/controllers/product_controller.rb +++ b/app/controllers/product_controller.rb @@ -51,7 +51,7 @@ class ProductController < ApplicationController end else flash[:message] = 'You are not authorized to create products.' - redirect_to :controller => :project, :action => :view, :id => @project.id + redirect_to project_path(@project) end end
diff --git a/app/controllers/project_controller.rb b/app/controllers/project_controller.rb deleted file mode 100644 index b122159..0000000 --- a/app/controllers/project_controller.rb +++ /dev/null @@ -1,102 +0,0 @@ -# project_controller.rb -# Copyright (C) 2008, Darryl L. Pierce mcpierce@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/. -# - -# +ProjectController+ handles requests relating to the management and viewing of -# +Product+s. -# -class ProjectController < ApplicationController - before_filter :authenticated, :only => [:create, :modify] - before_filter :load_project, :except => [:create, :index] - before_filter :setup_for_edit, :only => [:create, :modify] - - # Allows viewing of all defined projects. - # - def index - @projects = Project.paginate :page => params[:page], :per_page => 10 - end - - # Shows a single project. - # - def view - @products = Product.paginate_by_project_id @project.id, :page => params[:page], :per_page => 10 - end - - # Begins the process of creating a new project. - # - def create - if @user.create_projects? - if request.post? - begin - Project.transaction do - @project = Project.new(params[:project]) - @project.save! - - redirect_to :action => :index - end - rescue ActiveRecord::RecordInvalid => error - @project.valid? - render :action => :create - end - else - @project = Project.new - end - else - flash[:message] = 'That action requires administrative rights.' - redirect_to :controller => :home, :action => :dashboard - end - end - - # Modifies an existing project. - # - def modify - if @user.can_modify_project?(@project) - if request.post? - begin - Project.transaction do - @project.update_attributes(params[:project]) - @project.save! - - redirect_to :action => :view, :id => @project - end - rescue ActiveRecord::RecordInvalid => error - @project.valid? - render :action => :modify - end - end - else - flash[:message] = "You are not authorized to modify that project." - redirect_to error_path - end - end - - private - - # Loads the requested project. - # - def load_project - @project = Project.find_by_id(params[:id]) - - unless @project - flash[:message] = 'Invalid project specified.' - redirect_to error_path - end - end - - def setup_for_edit - @users = User.find(:all, :order => 'display_name ASC') - end -end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb new file mode 100644 index 0000000..6c379b7 --- /dev/null +++ b/app/controllers/projects_controller.rb @@ -0,0 +1,142 @@ +# projects_controller.rb +# Copyright (C) 2008, Darryl L. Pierce mcpierce@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/. +# + +# +ProjectsController+ handles requests relating to the management and viewing +# of +Product+s. +# +class ProjectsController < ApplicationController + before_filter :authenticated, :only => [:new, :create, :edit, :update] + before_filter :load_project, :except => [:index, :new, :create, :destroy] + before_filter :setup_for_edit, :only => [:new, :create, :edit] + + # GET /projects + def index + @projects = Project.paginate :page => params[:page], :per_page => 10 + + respond_to do |format| + format.html + end + end + + # GET /projects/1 + def show + @products = Product.paginate_by_project_id @project.id, :page => params[:page], :per_page => 10 + + respond_to do |format| + format.html + end + end + + # get /projects/new + def new + if @user.create_projects? + @project = Project.new(:owner_id => @user.id) + else + flash[:error] = "You are not authorized to create projects." + + redirect_to error_url + end + end + + # GET /projects/1;edit + def edit + unless @project.user_can_modify?(@user) + flash[:message] = "You are not authorized to modify that project." + redirect_to project_path(@project) + end + end + + # POST /projects + def create + respond_to do |format| + if @user.create_projects? + @project = Project.new(params[:project]) + + begin + Project.transaction do + if @project.save + flash[:message] = "Project '#{@project.name}' created!" + format.html { redirect_to project_url(@project) } + else + @project.valid? + format.html { render :action => "new" } + end + end + rescue Exception => error + flash[:error] = "ERROR: #{error.message}" + format.html { redirect_to error_url } + end + else + flash[:error] = "You are not authorized to create projects." + format.html { redirect_to error_url } + end + end + end + + # PUT /projects/1 + def update + respond_to do |format| + if @project.user_can_modify?(@user) + begin + Project.transaction do + @project.update_attributes(params[:project]) + if @project.save! + flash[:message] = "Project was successfully updated." + format.html { redirect_to project_path(@project) } + else + @project.valid? + format.html { render :action => 'edit'} + end + 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." + format.html { redirect_to project_path(@project) } + end + end + end + + # DELETE /projects/1 + def destroy + respond_to do |format| + flash[:message] = "Project deletion is not current supported." + format.html { redirect_to error_url} + end + end + + private + + # Loads the requested project. + # + def load_project + @project = Project.find_by_id(params[:id]) + + unless @project + flash[:message] = 'Invalid project specified.' + respond_to do |format| + format.html { redirect_to error_path } + end + end + end + + def setup_for_edit + @users = User.find(:all, :order => 'display_name ASC') + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 96d59a7..88cd918 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,19 +1,19 @@ # application_helper.rb # Copyright (C) 2008, Darryl L. Pierce mcpierce@gmail.com -# +# # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation, either version 3 of the License, or (at your option) any later # version. -# +# # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. -# +# # You should have received a copy of the GNU General Public License along with # this program. If not, see http://www.gnu.org/licenses/. -# +#
module ApplicationHelper # Returns the first sentence from the supplied text, up to the first period. @@ -23,13 +23,13 @@ module ApplicationHelper if (text == nil) || text.empty? return " " end - + return text.slice(/^[^.]*.?/) - + end - + # Creates a link to a user. - # + # def link_to_user(user) if user @template.link_to(user.display_name, @@ -38,9 +38,9 @@ module ApplicationHelper :id => user) end end - + # Creates a link to an owner for a project, product or other item. - # + # def link_to_owner(owner, args = nil) if owner link_to_user(owner) @@ -49,61 +49,52 @@ module ApplicationHelper args[:unowned] if args end end - - # Creates a link to a project. - # - def link_to_project(project) - @template.link_to(project.name, - :controller => :project, - :action => :view, - :id => project) - end - + # Creates a link to a product. - # - def link_to_product(product, options = {}) - @template.link_to(options[:text] ? options[:text] : product.name, + # + def link_to_product(product) + @template.link_to(product.name, :controller => :product, - :action => options[:action] ? options[:action] : :view, + :action => :view, :id => product) end - + # Creates a link to a sprint. - # + # def link_to_sprint(sprint) @template.link_to(sprint.title, :controller => :sprint, :action => :view, :id => sprint) end - + # Displays a link and image reporting the health of the sprint def show_sprint_health(sprint) @template.image_tag( sprint.healthy? ? "/images/icons/healthy.png" : "/images/icons/unhealthy.png", :alt => sprint.healthy? ? "Sprint is healthy" : "Sprint is not healthy") end - + # Creates a link to a user story. - # + # def link_to_user_story(user_story, options ={}) @template.link_to((options[:text] ? options[:text] : user_story.title), :controller => :user_story, :action => (options[:action] ? options[:action] : :view), :id => user_story) end - + # Creates a link to a backlog item. - # + # def link_to_backlog_item(backlog_item, options = {}) @template.link_to(options[:text] ? options[:text] : backlog_item.title, :controller => :backlog, :action => (options[:action] ? options[:action] : :view), :id => backlog_item.id) end - + # Shows the hours for a given object as estimated, actual and remaining. - # + # def show_hours_as_ear(estimated) format("%0.1f/%0.1f/%0.1f",estimated.estimated_hours, estimated.actual_hours, estimated.remaining_hours) end diff --git a/app/models/project.rb b/app/models/project.rb index 2bd9541..6a7ce5d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -21,14 +21,25 @@ class Project < ActiveRecord::Base validates_presence_of :name, :message => 'A project has to have a name.' - + validates_length_of :name, + :minimum => 4, + :message => 'The project name must be at least four characters long.' validates_uniqueness_of :name, :message => 'This name is used by an existing project.'
+ validates_presence_of :owner_id, + :message => 'A project must have an owner.' + belongs_to :owner, :class_name => 'User', :foreign_key => :owner_id
has_many :products
+ # Returns whether the user can modify this project. + # + def user_can_modify?(user) + user && (user.privileges.admin_projects || (user.id == owner.id)) + end + # Returns whether the user can create products for this project. # def can_create_products?(user) diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb index ac4dd6f..e1ac558 100644 --- a/app/views/layouts/default.html.erb +++ b/app/views/layouts/default.html.erb @@ -24,7 +24,7 @@
<div id="user-box"> <%= link_to "Home", :controller => :home %> - <%= link_to "Projects", :controller => :project, :action => :index %> + <%= link_to "Projects", projects_path %> <%= link_to "Reports", :controller => :report, :action => :index %> <% if @user %> <%= link_to @user.display_name, dashboard_url %> diff --git a/app/views/product/_details.html.erb b/app/views/product/_details.html.erb index d7e1bda..7ea0794 100644 --- a/app/views/product/_details.html.erb +++ b/app/views/product/_details.html.erb @@ -14,7 +14,7 @@
<tr> <td class="label">For Project:</td> - <td class="value"><%= link_to_project @product.project %></td> + <td class="value"><%= link_to @product.project.name, project_path(@product.project) %></td> </tr>
<tr> diff --git a/app/views/project/_details.html.erb b/app/views/project/_details.html.erb deleted file mode 100644 index 7dfc64c..0000000 --- a/app/views/project/_details.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -<table class="details"> - <thead> - <tr> - <th class="title" colspan="2"><%= "Details For #{@project.name}" %></th> - </tr> - </thead> - - <tbody> - <tr> - <td class="label">Owner:</td> - <td class="value"><%= link_to_user @project.owner %></td> - </tr> - - <tr> - <td class="label">Homepage:</td> - <td class="value"><%= link_to_homepage @project %> - </tr> - - <tr> - <td class="text" colspan="2"> - <%= simple_format @project.description %> - </td> - </tr> - </tbody> -</table> diff --git a/app/views/project/_edit.html.erb b/app/views/project/_edit.html.erb deleted file mode 100644 index d1b02e9..0000000 --- a/app/views/project/_edit.html.erb +++ /dev/null @@ -1,59 +0,0 @@ -<% form_for :project do |form| %> - - <% unless @project.new_record? %> - <%= form.hidden_field :id %> - <% end %> - - <table class="edit"> - <tbody> - <tr> - <td class="label">Project name</td> - <td class="value"><%= form.text_field :name %></td> - </tr> - <tr> - <td /><td class="errors"><%= error_message_on(:project, :name) %> - </tr> - - <tr> - <td class="label">Website</td> - <td class="value"><%= form.text_field :url %></td> - </tr> - <tr> - <td /><td class="errors"><%= error_message_on(:project, :url) %> - </tr> - - <tr> - <td class="label">Owner</td> - <td class="value"> - <% if @user.privileges.admin_projects %> - <%= collection_select :project, :owner_id, @users, :id, - :display_name, {:include_blank => true} %> - <% else %> - <% if @project.owner %> - <%= h @project.owner.display_name %> - <% else %> - UNOWNED - <% end %> - <% end %> - </td> - <td /><td class="errors"><%= error_message_on(:project, :owner) %> - </tr> - - <tr> - <td class="label">Description</td> - <td class="value"><%= form.text_area :description %></td> - </tr> - - <tr> - <td class="buttons" colspan="2"> - <% if @project.new_record? %> - <%= submit_tag "Create", :class => 'button' %> - <% else %> - <%= submit_tag "Update", :class => 'button' %> - <% end %> - </td> - </tr> - </tbody> - </table> - -<% end %> \ No newline at end of file diff --git a/app/views/project/_product.html.erb b/app/views/project/_product.html.erb deleted file mode 100644 index 51766eb..0000000 --- a/app/views/project/_product.html.erb +++ /dev/null @@ -1,19 +0,0 @@ -<tr> - <td><%= link_to "#{product.name}", - {:controller => :product, :action => :view, :id => product} %> - </td> - <td> - <% if product.owner != nil %> - <%= link_to(product.owner.display_name, - {:controller => :user, - :action => :view, - :id => product.owner})%> - - (<%= mail_to(product.owner.email, "email") %>) - <% else %> - None (want to become the owner?) - <% end %> - </td> - <td class="description"><%= h product.description %></td> - <td class="number"><%= product.backlog.size %></td> -</tr> diff --git a/app/views/project/create.html.erb b/app/views/project/create.html.erb deleted file mode 100644 index 0ae005d..0000000 --- a/app/views/project/create.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render(:partial => 'edit', :object => @project) %> diff --git a/app/views/project/index.html.erb b/app/views/project/index.html.erb deleted file mode 100644 index d472b78..0000000 --- a/app/views/project/index.html.erb +++ /dev/null @@ -1,48 +0,0 @@ -<div class="toolbar"> - <% if @user && @user.create_projects? %> - <%= link_to "New Project", :action => :create %> - <% end %> -</div> - -<%= will_paginate @projects %> - -<table class="list"> - <colgroup> - <col class="row_id" /> - <col class="name" /> - <col class="description" /> - <col class="user" /> - <col class="date" /> - </colgroup> - <thead> - <tr> - <th class="title" colspan="5">Projects</th> - </tr> - <tr> - <th>##</th> - <th>Name</th> - <th>Description</th> - <th>Owner</th> - <th>Created</th> - </tr> - </thead> - - <tbody> - <% if @projects.empty? %> - <tr><td colspan="5">There are no projects defined.</td></tr> - <% else %> - <% @projects.each_with_index do |project, i| %> - <% row_class = i%2 == 0 ? 'even' : 'odd' %> - - <tr class="<%= row_class %>"> - <td class="row_id"><%= i + 1 %></td> - <td><%= link_to_project project %></td> - <td><%= get_first_sentence project.description %></td> - <td><%= link_to_owner project.owner, 'Current Unowned' %></td> - <td><%= project.created_at.to_s(:date) %></td> - </tr> - - <% end %> - <% end %> - </tbody> -</table> diff --git a/app/views/project/modify.html.erb b/app/views/project/modify.html.erb deleted file mode 100644 index 0ae005d..0000000 --- a/app/views/project/modify.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render(:partial => 'edit', :object => @project) %> diff --git a/app/views/project/view.html.erb b/app/views/project/view.html.erb deleted file mode 100644 index c501d67..0000000 --- a/app/views/project/view.html.erb +++ /dev/null @@ -1,59 +0,0 @@ -<div style="width: 100%; overflow: auto;"> - <div id="details" style="float: left; width: 33%;"> - <div class="toolbar"> - <% if @user && @user.can_modify_project?(@project) %> - <%= link_to "Edit project...", :action => :modify, :id => @project %> - <% end %> - </div> - <%= render :partial => 'details', :object => @project %> - </div> - - <div id="products" style="float: right; width: 66%;"> - <div class="toolbar"> - <%= will_paginate @products %> - <% if @project.can_create_products?(@user) %> - <%= link_to "Create Product...", - { - :controller => :product, - :action => :create, - :project => @project - } %> - <% end %> - </div> - <table class="list"> - <colgroup> - <col class="row_id" /> - <col class="name" /> - <col class="description" /> - <col class="user" /> - <col class="date" /> - </colgroup> - - <thead> - <tr> - <th>##</th> - <th>Product</th> - <th>Description</th> - <th>Owner</th> - <th>Created</th> - </tr> - </thead> - - <tbody> - <% @products.each_with_index do |product, i| %> - <% row_class = i%2 == 0 ? 'even' : 'odd' %> - - <tr class="<%= row_class %>" - onmouseover="this.className='hot'" - onmouseout="this.className='<%= row_class %>' "> - <td class="row_id"><%= i + 1 %></td> - <td><%= link_to_product product %></td> - <td><%= get_first_sentence product.description %></td> - <td><%= link_to_owner product.owner %></td> - <td><%= product.created_at.to_s(:date) %></td> - </tr> - <% end %> - </tbody> - </table> - </div> -</div> diff --git a/app/views/projects/_details.html.erb b/app/views/projects/_details.html.erb new file mode 100644 index 0000000..9fe7b4b --- /dev/null +++ b/app/views/projects/_details.html.erb @@ -0,0 +1,25 @@ +<table class="details"> + <thead> + <tr> + <th class="title" colspan="2"><%= "Details For #{@project.name}" %></th> + </tr> + </thead> + + <tbody> + <tr> + <td class="label">Owner:</td> + <td class="value"><%= link_to_user @project.owner %></td> + </tr> + + <tr> + <td class="label">Homepage:</td> + <td class="value"><%= link_to_homepage @project %> + </tr> + + <tr> + <td class="text" colspan="2"> + <%= simple_format @project.description %> + </td> + </tr> + </tbody> +</table> diff --git a/app/views/projects/_edit.html.erb b/app/views/projects/_edit.html.erb new file mode 100644 index 0000000..0b5d409 --- /dev/null +++ b/app/views/projects/_edit.html.erb @@ -0,0 +1,58 @@ +<% html = @project.new_record? ? {:method => :post} : {:method => :put} %> + +<% form_for :project, @project, :url => project_path(@project), :html => html do |form| %> + <table class="edit"> + <tbody> + <tr> + <td class="label">Project name</td> + <td class="value"> + <%= form.text_field :name %> + <%= error_message_on(:project, :name) %> + </td> + </tr> + + <tr> + <td class="label">Website</td> + <td class="value"> + <%= form.text_field :url %> + <%= error_message_on(:project, :url) %> + </td> + </tr> + + <tr> + <td class="label">Owner</td> + <td class="value"> + <% if @user.privileges.admin_projects %> + <%= collection_select :project, :owner_id, @users, :id, + :display_name, {:include_blank => true} %> + <% else %> + <% if @project.owner %> + <%= h @project.owner.display_name %> + <% else %> + UNOWNED + <% end %> + <% end %> + <%= error_message_on(:project, :owner) %> + </td> + </tr> + + <tr> + <td class="label">Description</td> + <td class="value"> + <%= form.text_area :description %> + <%= error_message_on(:project, :description) %> + </td> + </tr> + + <tr> + <td class="buttons" colspan="2"> + <% if @project.new_record? %> + <%= submit_tag "Create", :class => 'button' %> + <% else %> + <%= submit_tag "Update", :class => 'button' %> + <% end %> + </td> + </tr> + </tbody> + </table> +<% end %> \ No newline at end of file diff --git a/app/views/projects/_product.html.erb b/app/views/projects/_product.html.erb new file mode 100644 index 0000000..51766eb --- /dev/null +++ b/app/views/projects/_product.html.erb @@ -0,0 +1,19 @@ +<tr> + <td><%= link_to "#{product.name}", + {:controller => :product, :action => :view, :id => product} %> + </td> + <td> + <% if product.owner != nil %> + <%= link_to(product.owner.display_name, + {:controller => :user, + :action => :view, + :id => product.owner})%> + + (<%= mail_to(product.owner.email, "email") %>) + <% else %> + None (want to become the owner?) + <% end %> + </td> + <td class="description"><%= h product.description %></td> + <td class="number"><%= product.backlog.size %></td> +</tr> diff --git a/app/views/projects/edit.html.erb b/app/views/projects/edit.html.erb new file mode 100644 index 0000000..0ae005d --- /dev/null +++ b/app/views/projects/edit.html.erb @@ -0,0 +1 @@ +<%= render(:partial => 'edit', :object => @project) %> diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb new file mode 100644 index 0000000..d4008f5 --- /dev/null +++ b/app/views/projects/index.html.erb @@ -0,0 +1,56 @@ +<div class="toolbar"> + <% if @user && @user.create_projects? %> + <%= link_to "New Project", new_project_path %> + <% end %> +</div> + +<%= will_paginate @projects %> + +<table class="list"> + <colgroup> + <col class="row_id" /> + <col class="name" /> + <col class="description" /> + <col class="user" /> + <col class="date" /> + <col class="actions" /> + </colgroup> + <thead> + <tr> + <th class="title" colspan="6">Projects</th> + </tr> + <tr> + <th>##</th> + <th>Name</th> + <th>Description</th> + <th>Owner</th> + <th>Created</th> + <th>Actions</th> + </tr> + </thead> + + <tbody> + <% if @projects.empty? %> + <tr><td colspan="6">There are no projects defined.</td></tr> + <% else %> + <% @projects.each_with_index do |project, i| %> + <% row_class = i%2 == 0 ? 'even' : 'odd' %> + + <tr class="<%= row_class %>"> + <td class="row_id"><%= i + 1 %></td> + <td><%= link_to project.name, project_path(project) %></td> + <td><%= get_first_sentence project.description %></td> + <td><%= link_to_owner project.owner, 'Current Unowned' %></td> + <td><%= project.created_at.to_s(:date) %></td> + <td> + <%= link_to "View", project_path(project) %> + <% if project.user_can_modify?(@user) %> + <%= link_to "Edit", edit_project_path(project) %> + <% end %> + </td> + </tr> + + <% end %> + <% end %> + </tbody> +</table> diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb new file mode 100644 index 0000000..0ae005d --- /dev/null +++ b/app/views/projects/new.html.erb @@ -0,0 +1 @@ +<%= render(:partial => 'edit', :object => @project) %> diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb new file mode 100644 index 0000000..f8fe791 --- /dev/null +++ b/app/views/projects/show.html.erb @@ -0,0 +1,59 @@ +<div style="width: 100%; overflow: auto;"> + <div id="details" style="float: left; width: 33%;"> + <div class="toolbar"> + <% if @project.user_can_modify?(@user) %> + <%= link_to "Edit", edit_project_path(@project)%> + <% end %> + </div> + <%= render :partial => 'details', :object => @project %> + </div> + + <div id="products" style="float: right; width: 66%;"> + <div class="toolbar"> + <%= will_paginate @products %> + <% if @project.can_create_products?(@user) %> + <%= link_to "Create Product...", + { + :controller => :product, + :action => :create, + :project => @project + } %> + <% end %> + </div> + <table class="list"> + <colgroup> + <col class="row_id" /> + <col class="name" /> + <col class="description" /> + <col class="user" /> + <col class="date" /> + </colgroup> + + <thead> + <tr> + <th>##</th> + <th>Product</th> + <th>Description</th> + <th>Owner</th> + <th>Created</th> + </tr> + </thead> + + <tbody> + <% @products.each_with_index do |product, i| %> + <% row_class = i%2 == 0 ? 'even' : 'odd' %> + + <tr class="<%= row_class %>" + onmouseover="this.className='hot'" + onmouseout="this.className='<%= row_class %>' "> + <td class="row_id"><%= i + 1 %></td> + <td><%= link_to_product product %></td> + <td><%= get_first_sentence product.description %></td> + <td><%= link_to_owner product.owner %></td> + <td><%= product.created_at.to_s(:date) %></td> + </tr> + <% end %> + </tbody> + </table> + </div> +</div> diff --git a/app/views/projects/update.html.erb b/app/views/projects/update.html.erb new file mode 100644 index 0000000..0ae005d --- /dev/null +++ b/app/views/projects/update.html.erb @@ -0,0 +1 @@ +<%= render(:partial => 'edit', :object => @project) %> diff --git a/app/views/tasks/new.html.erb b/app/views/tasks/new.html.erb index ae21641..ee1119f 100644 --- a/app/views/tasks/new.html.erb +++ b/app/views/tasks/new.html.erb @@ -1,5 +1,3 @@ <div> - <% form_for(:task, @task, :url => task_path(@task)) do |form| %> - <%= render :partial => 'edit', :object => @task %> - <% end %> + <%= render(:partial => 'edit', :object => @project) %> </div> diff --git a/config/routes.rb b/config/routes.rb index 2f66a65..c1f20fc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,11 +16,12 @@ #
ActionController::Routing::Routes.draw do |map| + map.resources :projects map.resources :tasks
# You can have the root of your site routed with map.root -- just remember to # delete public/index.html. - map.root :controller => 'project' + map.root :controller => 'home'
# Login URL map.login "/login", :controller => 'home', :action => 'login' diff --git a/test/functional/product_controller_test.rb b/test/functional/product_controller_test.rb index acca9e7..f008cbb 100644 --- a/test/functional/product_controller_test.rb +++ b/test/functional/product_controller_test.rb @@ -84,7 +84,7 @@ class ProductControllerTest < ActionController::TestCase {:project => @project.id}, {:user_id => users(:jdonuts).id}
- assert_redirected_to :controller => :project, :action => :view, :id => @project.id + assert_redirected_to project_url(@project) end
# Ensures that someone with project admin rights but who isn't the project @@ -95,7 +95,7 @@ class ProductControllerTest < ActionController::TestCase {:project => @project.id}, {:user_id => @non_project_owner.id}
- assert_redirected_to :controller => :project, :action => :view, :id => @project.id + assert_redirected_to project_url(@project) end
# Ensures that calling create initially works as expected. diff --git a/test/functional/project_controller_test.rb b/test/functional/project_controller_test.rb deleted file mode 100644 index 347e795..0000000 --- a/test/functional/project_controller_test.rb +++ /dev/null @@ -1,176 +0,0 @@ -# project_controller_test.rb -# Copyright (C) 2008, Darryl L. Pierce mcpierce@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' - -# +ProjectControllerTest+ performs tests on +ProjectController+ to ensure that -# it works as expected. -# -class ProjectControllerTest < ActionController::TestCase - fixtures :projects - fixtures :users - - def setup - @project = projects(:cairo) - @admin = @project.owner - @nonadmin = users(:jdonuts) - - raise "Admin and non-admin cannot be the same person." if @admin.id == @nonadmin.id - end - - # Ensures that viewing the list of projects works as expected. - # - def test_index - get :index - - assert_response :success - assert assigns['projects'] - end - - # Ensures that viewing without a project id shows an error. - # - def test_view_without_id - get :view - - assert_redirected_to error_path - end - - # Ensures that viewing a project works as expected. - # - def test_view - get :view, {:id => @project.id} - - assert_response :success - assert_equal 2, assigns['products'].size, - 'Did not load the set of products.' - end - - # Ensures that an anonymous user cannot create a new project. - # - def test_create_for_anonymous_user - get :create - - assert_redirected_to :controller => :home, :action => :login - end - - # Ensures that a user who does not have project admin rights cannot create a - # new project. - # - def test_create_for_non_admin - get :create, - nil, - {:user_id => @nonadmin.id} - - assert_redirected_to :controller => :home, :action => :dashboard - end - - # Ensures that create works as expected. - # - def test_create - get :create, - {}, - {:user_id => @admin.id} - - assert_response :success - assert assigns['project'] - assert assigns['users'] - end - - # Ensures the controller redisplays the edit form when the project is invalid. - # - def test_create_as_save_with_invalid_project - post :create, {:project => {:owner_id => @admin.id}}, {:user_id => @admin.id} - - assert_response :success - assert_template 'project/create' - end - - # Ensures that saving a project works as expected. - # - def test_create_as_save - project_details = { - :name => 'project1', - :owner_id => @admin.id, - :url => 'http://www.project.org/', - :description => 'This is a new project' - } - - post :create, - {:project => project_details}, - {:user_id => @admin.id} - - assert_redirected_to :action => :index - - result = Project.find_by_name(project_details[:name]) - - assert result, 'Project was not saved.' - end - - # Ensures that anonymous users cannot modify a project. - # - def test_modify_for_anonymous_user - get :modify - - assert_redirected_to :controller => :home, :action => :login - end - - # Ensures that modifying an invalid project results in an error. - # - def test_modify_for_invalid_project - post :modify, - {:id => 9999}, - {:user_id => @admin.id} - - assert_redirected_to error_path - end - - # Ensures that unauthorized users cannot modify a project. - # - def test_modify_for_unauthorized_user - get :modify, - {:id => @project.id}, - {:user_id => @nonadmin.id} - - assert_redirected_to error_path - end - - # Ensures that starting to modify a project works as expected. - # - def test_modify - get :modify, - {:id => @project.id}, - {:user_id => @project.owner_id} - - assert_response :success - end - - # Ensures that modifying an existing project works as expected. - # - def test_modify_as_save - project_details = {:name => 'newname1'} - - post :modify, - {:id => @project.id, :project => project_details}, - {:user_id => @project.owner_id} - - assert_redirected_to :action => :view - - result = Project.find_by_id(@project.id) - - assert_equal project_details[:name], result.name, 'Project was not modified.' - end -end diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb new file mode 100644 index 0000000..2e3e303 --- /dev/null +++ b/test/functional/projects_controller_test.rb @@ -0,0 +1,233 @@ +# projects_controller_test.rb +# Copyright (C) 2008, Darryl L. Pierce mcpierce@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' + +# +ProjectsControllerTest+ performs tests on +ProjectController+ to ensure that +# it works as expected. +# +class ProjectsControllerTest < ActionController::TestCase + fixtures :projects + fixtures :users + + def setup + @project = projects(:cairo) + @owner = @project.owner + @nonowner = users(:jdonuts) + raise "Owner and nonowner cannot be the same user!" if @owner.id == @nonowner.id + + @nonadmin = @nonowner + @admin = users(:project_admin) + raise "Nonadmin and admin cannot be the same user!" if @nonadmin.id == @admin.id + end + + # Ensures that showing the project index works as expected. + # + def test_index + get :index + + assert_response :success + assert assigns['projects'], "Didn't load any projects." + end + + # Ensures that showing a single project requires an id. + # + def test_show_without_id + get :show + + assert_redirected_to error_url + end + + # Ensures that showing a project fails on invalid ids. + # + def test_show_with_invalid_id + get :show, {:id => 9999} + + assert_redirected_to error_url + end + + # Ensures tha show a project works as expected. + # + def test_show + get :show, {:id => @project.id} + + assert_response :success + assert assigns['project'], "Failed to load the project." + assert_equal @project.id, assigns['project'].id, + "Failed to load the correct project." + end + + # Ensures that an anonymous user cannot create a new project. + # + def test_new_as_anonymous + get :new + + assert_redirected_to :controller => :home, :action => :login + end + + # Ensures that a user without project admin privileges cannot create a + # project. + # + def test_new_as_unauthorized_user + get :new, {}, {:user_id => @nonadmin.id} + + assert_redirected_to error_url + end + + # Ensures that starting off a new project works as expected. + # + def test_new + get :new, {}, {:user_id => @admin.id} + + assert_response :success + assert assigns['project'], "Did not create a new project." + assert_equal @admin.id, assigns['project'].owner_id, + "Did not assign the default owner." + assert assigns['users'], "Did not load the list of users." + end + + # Ensures an anonymous user cannot start editing a project. + # + def test_edit_as_anonymous + get :edit + + assert_redirected_to :controller => :home, :action => :login + end + + # Ensures that edit fails on an invalid id. + # + def test_edit_with_invalid_id + get :edit, + {:id => 9999}, + {:user_id => @owner.id} + + assert_redirected_to error_url + end + + # Ensures that a nonowner cannot edit a project. + # + def test_edit_as_nonowner + get :edit, + {:id => @project.id}, + {:user_id => @nonowner.id} + + assert_redirected_to project_path(@project) + end + + # Ensures that the owner can edit a project. + # + def test_edit + get :edit, + {:id => @project.id}, + {:user_id => @owner.id} + + assert_response :success + assert assigns['project'], "Failed to load a project." + assert_equal @project.id,assigns['project'].id, + "Failed to load the correct project." + end + + # Ensures that an anonymous user cannot create a project. + # + def test_create_as_anonymous + post :create + + assert_redirected_to login_url + end + + # Ensures that a non-admin cannot create a project. + # + def test_create_as_nonadmin + post :create, {}, {:user_id => @nonadmin.id} + + assert_redirected_to error_url + end + + # Ensures that an invalid project returns the user to the edit page. + # + def test_create_with_invalid_project + post :create, + {:project => {}}, + {:user_id => @admin.id} + + assert_response :success + end + + # Ensures that a project is created when one is submitted. + # + def test_create + post :create, + {:project => {:name => 'test', :owner_id => @admin.id}}, + {:user_id => @admin.id} + + assert_redirected_to project_path(assigns['project']) + end + + # Ensures that an anonymous user cannot update a project. + # + def test_update_as_anonymous + put :update + + assert_redirected_to login_url + end + + # Ensures that a valid project id must be provided. + # + def test_update_with_invalid_id + put :update, + {:id => 9999}, + {:user_id => @admin.id} + + assert_redirected_to error_url + end + + # Ensures that a nonadmin cannot update a project. + # + def test_update_by_nonowner + put :update, + {:id => @project.id, + :project => {:name => 'newname'}}, + {:user_id => @nonowner.id} + + assert_redirected_to project_path(@project) + result = Project.find_by_id(@project.id) + assert_equal @project.name, result.name, + "Project should not have been updated!" + end + + # Ensures that the owner can edit a project. + # + def test_update + put :update, + {:id => @project.id, + :project => {:name => 'newname'}}, + {:user_id => @owner.id} + + assert_redirected_to project_path(@project) + result = Project.find_by_id(@project.id) + assert_equal 'newname', result.name, + "Project should have been updated!" + end + + # Ensures that the destroy method just exists. + # + def test_destroy + delete :destroy + + assert_redirected_to error_url + end +end