[refs #54] Base logic and templates for issues and comments to them
This commit is contained in:
parent
df61ee8459
commit
d20d43eb2b
1
Gemfile
1
Gemfile
|
@ -22,6 +22,7 @@ gem 'paperclip', "~> 2.3"
|
|||
gem "will_paginate", "~> 3.0.2"
|
||||
gem 'meta-tags', '~> 1.2.4', :require => 'meta_tags'
|
||||
gem "russian"
|
||||
gem "friendly_id", "~> 4.0.0.beta14"
|
||||
|
||||
# gem 'ghoul_grack', '~> 0.0.1'
|
||||
gem 'grack', :git => 'git://github.com/rdblue/grack.git', :require => 'git_http'
|
||||
|
|
|
@ -77,6 +77,7 @@ GEM
|
|||
factory_girl_rails (1.4.0)
|
||||
factory_girl (~> 2.3.0)
|
||||
railties (>= 3.0.0)
|
||||
friendly_id (4.0.0.beta8)
|
||||
grit (2.4.1)
|
||||
diff-lcs (~> 1.1)
|
||||
mime-types (~> 1.15)
|
||||
|
@ -219,6 +220,7 @@ DEPENDENCIES
|
|||
delayed_job
|
||||
devise (~> 1.5.2)
|
||||
factory_girl_rails (~> 1.4.0)
|
||||
friendly_id (~> 4.0.0.beta14)
|
||||
grack!
|
||||
grit
|
||||
haml-rails (~> 0.3.4)
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
class CommentsController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
|
||||
def index
|
||||
@commentable = find_commentable
|
||||
@comments = @commentable.comments
|
||||
end
|
||||
|
||||
def create
|
||||
@commentable = find_commentable
|
||||
@comment = @commentable.comments.build(params[:comment])
|
||||
if @comment.save
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to :id => nil
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.saved_error")
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@comment = Comment.find(params[:id])
|
||||
if @comment.update_attributes(params[:comment])
|
||||
flash[:notice] = I18n.t("flash.comment.saved")
|
||||
redirect_to :id => nil
|
||||
else
|
||||
flash[:error] = I18n.t("flash.comment.saved_error")
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@comment = Comment.find(params[:id])
|
||||
@comment.destroy
|
||||
|
||||
flash[:notice] = t("flash.comment.destroyed")
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_commentable
|
||||
params.each do |name, value|
|
||||
if name =~ /(.+)_id$/
|
||||
return $1.classify.constantize.find(value)
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -0,0 +1,58 @@
|
|||
class IssuesController < ApplicationController
|
||||
before_filter :authenticate_user!
|
||||
before_filter :find_project
|
||||
before_filter :find_issue, :only => [:show, :edit, :update, :destroy]
|
||||
|
||||
load_and_authorize_resource
|
||||
autocomplete :user, :uname
|
||||
|
||||
def index
|
||||
@issues = @project.issues.paginate :per_page => 10, :page => params[:page]
|
||||
end
|
||||
|
||||
def create
|
||||
@user_id = params[:user_id]
|
||||
@user_uname = params[:user_uname]
|
||||
|
||||
@issue = Issue.new(params[:issue])
|
||||
@issue.user_id = @user_id
|
||||
@issue.project_id = @project.id
|
||||
if @issue.save!
|
||||
flash[:notice] = I18n.t("flash.issue.saved")
|
||||
redirect_to project_issues_path(@project)
|
||||
else
|
||||
flash[:error] = I18n.t("flash.issue.saved_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@user_id = params[:user_id]
|
||||
@user_uname = params[:user_uname]
|
||||
|
||||
if @issue.update_attributes( params[:issue].merge({:user_id => @user_id}) )
|
||||
flash[:notice] = I18n.t("flash.issue.saved")
|
||||
redirect_to @issue
|
||||
else
|
||||
flash[:error] = I18n.t("flash.issue.saved_error")
|
||||
render :action => :new
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@issue.destroy
|
||||
|
||||
flash[:notice] = t("flash.issue.destroyed")
|
||||
redirect_to root_path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_project
|
||||
@project = Project.find(params[:project_id])
|
||||
end
|
||||
|
||||
def find_issue
|
||||
@issue = Issue.find(params[:id])
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module CommentsHelper
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
module IssuesHelper
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class Comment < ActiveRecord::Base
|
||||
belongs_to :commentable
|
||||
|
||||
validates :body, :commentable_id, :commentable_type, :presence => true
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
class Issue < ActiveRecord::Base
|
||||
STATUSES = ['open', 'close']
|
||||
|
||||
extend FriendlyId
|
||||
friendly_id :serial_id
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :user
|
||||
|
||||
has_many :comments, :as => :commentable
|
||||
|
||||
validates :title, :body, :project_id, :user_id, :presence => true
|
||||
|
||||
attr_readonly :serial_id
|
||||
|
||||
after_create :set_serial_id
|
||||
|
||||
protected
|
||||
|
||||
def set_serial_id
|
||||
serial_id = project.issues.count + 1
|
||||
save
|
||||
end
|
||||
end
|
|
@ -4,6 +4,7 @@ class Project < ActiveRecord::Base
|
|||
belongs_to :category, :counter_cache => true
|
||||
belongs_to :owner, :polymorphic => true
|
||||
|
||||
has_many :issues, :dependent => :destroy
|
||||
has_many :build_lists, :dependent => :destroy
|
||||
has_many :auto_build_lists, :dependent => :destroy
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.group
|
||||
= f.label :body, :class => :label
|
||||
= f.text_area :body, :class => 'text_field', :cols => 80
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save"))
|
||||
= t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), project_issue_comment_path(@issue.project, @issue), :class => "text_button_padding link_button"
|
|
@ -0,0 +1,10 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issue_path(@project, @issue)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.edit_header")
|
||||
.inner
|
||||
= form_for @comment, :url => project_issue_comment_path(@project, @issue, @comment), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -0,0 +1,25 @@
|
|||
= javascript_include_tag "autocomplete-rails.js"
|
||||
|
||||
.group
|
||||
= f.label :title, :class => :label
|
||||
= f.text_field :title, :class => 'text_field'
|
||||
|
||||
.group
|
||||
= f.label :body, :class => :label
|
||||
= f.text_area :body, :class => 'text_field', :cols => 80
|
||||
|
||||
.group
|
||||
= f.label :status, :class => :label
|
||||
= f.select :status, Issue::STATUSES, :class => 'text_field'
|
||||
|
||||
.group
|
||||
= label_tag "", t("layout.issues.user_id"), :class => :label
|
||||
= autocomplete_field_tag 'user_id', @user_uname, autocomplete_user_uname_platforms_path, :id_element => '#user_id_field'
|
||||
= hidden_field_tag 'user_id', @user_id, :id => 'user_id_field'
|
||||
|
||||
.group.navform.wat-cf
|
||||
%button.button{:type => "submit"}
|
||||
= image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save"))
|
||||
= t("layout.save")
|
||||
%span.text_button_padding= t("layout.or")
|
||||
= link_to t("layout.cancel"), project_path(@project), :class => "text_button_padding link_button"
|
|
@ -0,0 +1,15 @@
|
|||
%table.table
|
||||
%tr
|
||||
%th.first= t("activerecord.attributes.issue.title")
|
||||
%th.first= t("activerecord.attributes.issue.status")
|
||||
%th.last
|
||||
- @project.issues.each do |issue|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td
|
||||
= link_to issue.title, project_issue_path(@project, issue)
|
||||
%td
|
||||
= issue.status
|
||||
%td.last
|
||||
= link_to t("layout.show"), project_issue_path(@project, issue)
|
||||
|
|
||||
= link_to t("layout.delete"), project_issue_path(@project, issue), :method => :delete, :confirm => t("layout.issues.confirm_delete") if can? :destroy, issue
|
|
@ -0,0 +1,12 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.new"), new_project_issue_path(@project)
|
||||
%li.active= link_to t("layout.issues.edit"), edit_project_issue_path(@project)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.edit_header")
|
||||
.inner
|
||||
= form_for @issue, :url => project_issue_path(@issue), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -0,0 +1,14 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first.active= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.new"), new_project_issue_path(@project) if can? :create, Issue
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.list_header")
|
||||
.inner
|
||||
= render :partial => 'shared/search_form'
|
||||
= render :partial => 'issues/list', :object => @issues
|
||||
.actions-bar.wat-cf
|
||||
.actions
|
||||
= will_paginate @issues, :param_name => :issue_page
|
|
@ -0,0 +1,11 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to "#{t("layout.issues.list")}", project_issues_path(@project)
|
||||
%li.active= link_to "#{t("layout.issues.new")}", new_project_issue_path(@project)
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.new_header")
|
||||
.inner
|
||||
= form_for :issue, :url => project_issues_path(@project), :html => { :class => :form } do |f|
|
||||
= render :partial => "form", :locals => {:f => f}
|
|
@ -0,0 +1,53 @@
|
|||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
%li.first= link_to t("layout.issues.list"), project_issues_path(@project)
|
||||
%li= link_to t("layout.issues.edit"), edit_project_issue_path(@project, @issue) if can? :edit, @issue
|
||||
.content
|
||||
.inner
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.issue.title")
|
||||
\:
|
||||
= @issue.title
|
||||
%p
|
||||
%b
|
||||
= t("activerecord.attributes.issue.body")
|
||||
\:
|
||||
= @issue.body
|
||||
%p
|
||||
%b
|
||||
= t('layout.issues.status')
|
||||
\:
|
||||
= @issue.status
|
||||
|
||||
%a{ :name => "comments" }
|
||||
.block
|
||||
.secondary-navigation
|
||||
%ul.wat-cf
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.issues.comments_header")
|
||||
.inner
|
||||
%table.table
|
||||
%tr
|
||||
%th.first= t("activerecord.attributes.user.uname")
|
||||
%th.first= t("activerecord.attributes.comment.body")
|
||||
%th.last
|
||||
- @issue.comments.each do |comment|
|
||||
%tr{:class => cycle("odd", "even")}
|
||||
%td
|
||||
= comment.user.uname
|
||||
%td
|
||||
= comment.body
|
||||
%td.last
|
||||
= link_to t("layout.edit"), edit_project_issue_comment_path(@project, @issue, comment) if can? :update, comment
|
||||
= link_to image_tag("web-app-theme/icons/cross.png", :alt => t("layout.delete")) + " " + t("layout.delete"), project_issue_comment_path(@project, @issue, comment), :method => "delete", :class => "button", :confirm => t("layout.comment.confirm_delete") if can? :delete, comment
|
||||
|
||||
.block
|
||||
.content
|
||||
%h2.title
|
||||
= t("layout.comments.new_header")
|
||||
.inner
|
||||
= form_for :comment, :url => project_issue_comments_path(@project, @issue), :html => { :class => :form } do |f|
|
||||
= render :partial => "comments/form", :locals => {:f => f}
|
|
@ -6,6 +6,7 @@
|
|||
%li.active= link_to t("layout.projects.show"), project_path(@project)
|
||||
%li= link_to t("layout.git.repositories.source"), project_repo_path(@project)
|
||||
%li= link_to t("layout.projects.build"), build_project_path(@project)
|
||||
%li= link_to t("layout.projects.issues"), project_issues_path(@project)
|
||||
|
||||
.content
|
||||
.inner
|
||||
|
|
|
@ -68,6 +68,9 @@ Rosa::Application.routes.draw do
|
|||
end
|
||||
|
||||
resources :projects do
|
||||
resources :issues do
|
||||
resources :comments, :only => [:edit, :create, :update, :destroy]
|
||||
end
|
||||
resource :repo, :controller => "git/repositories", :only => [:show]
|
||||
resources :build_lists, :only => [:index, :show] do
|
||||
collection do
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
class CreateIssues < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :issues do |t|
|
||||
t.integer :serial_id
|
||||
t.integer :project_id
|
||||
t.integer :user_id
|
||||
t.string :title
|
||||
t.text :body
|
||||
t.string :status
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :issues, [:project_id, :serial_id], :unique => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :issues
|
||||
end
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
class CreateComments < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :comments do |t|
|
||||
t.integer :commentable_id
|
||||
t.string :commentable_type
|
||||
t.integer :user_id
|
||||
t.text :body
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :comments
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
class AddHasIssuesToProjects < ActiveRecord::Migration
|
||||
def self.up
|
||||
add_column :projects, :has_issues, :boolean, :default => true
|
||||
end
|
||||
|
||||
def self.down
|
||||
remove_column :projects, :has_issues
|
||||
end
|
||||
end
|
25
db/schema.rb
25
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20111130181101) do
|
||||
ActiveRecord::Schema.define(:version => 20111219073859) do
|
||||
|
||||
create_table "arches", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
|
@ -83,6 +83,15 @@ ActiveRecord::Schema.define(:version => 20111130181101) do
|
|||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "comments", :force => true do |t|
|
||||
t.integer "commentable_id"
|
||||
t.string "commentable_type"
|
||||
t.integer "user_id"
|
||||
t.text "body"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "containers", :force => true do |t|
|
||||
t.string "name", :null => false
|
||||
t.integer "project_id", :null => false
|
||||
|
@ -140,6 +149,19 @@ ActiveRecord::Schema.define(:version => 20111130181101) do
|
|||
t.string "uname"
|
||||
end
|
||||
|
||||
create_table "issues", :force => true do |t|
|
||||
t.integer "serial_id"
|
||||
t.integer "project_id"
|
||||
t.integer "user_id"
|
||||
t.string "title"
|
||||
t.text "body"
|
||||
t.string "status"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "issues", ["project_id", "serial_id"], :name => "index_issues_on_project_id_and_serial_id", :unique => true
|
||||
|
||||
create_table "platforms", :force => true do |t|
|
||||
t.string "description"
|
||||
t.string "name"
|
||||
|
@ -211,6 +233,7 @@ ActiveRecord::Schema.define(:version => 20111130181101) do
|
|||
t.integer "category_id"
|
||||
t.text "description"
|
||||
t.string "ancestry"
|
||||
t.boolean "has_issues", :default => true
|
||||
end
|
||||
|
||||
add_index "projects", ["category_id"], :name => "index_projects_on_category_id"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe CommentsController do
|
||||
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe IssuesController do
|
||||
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
# Read about factories at http://github.com/thoughtbot/factory_girl
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :comment do
|
||||
end
|
||||
end
|
|
@ -0,0 +1,6 @@
|
|||
# Read about factories at http://github.com/thoughtbot/factory_girl
|
||||
|
||||
FactoryGirl.define do
|
||||
factory :issue do
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the CommentsHelper. For example:
|
||||
#
|
||||
# describe CommentsHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# helper.concat_strings("this","that").should == "this that"
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
describe CommentsHelper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
# Specs in this file have access to a helper object that includes
|
||||
# the IssuesHelper. For example:
|
||||
#
|
||||
# describe IssuesHelper do
|
||||
# describe "string concat" do
|
||||
# it "concats two strings with spaces" do
|
||||
# helper.concat_strings("this","that").should == "this that"
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
describe IssuesHelper do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Comment do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Issue do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
Loading…
Reference in New Issue