diff options
-rw-r--r-- | site/app/controllers/approvals_controller.rb | 7 | ||||
-rw-r--r-- | site/app/models/agenda.rb | 12 | ||||
-rw-r--r-- | site/app/models/approval.rb | 27 | ||||
-rw-r--r-- | site/app/views/agendas/show.dryml | 16 | ||||
-rw-r--r-- | site/config/hobo_routes.rb | 8 | ||||
-rw-r--r-- | site/db/schema.rb | 12 | ||||
-rw-r--r-- | site/features/meeting_summary_approvals.feature | 28 | ||||
-rw-r--r-- | site/features/step_definitions/meeting_summary_approvals_steps.rb | 5 | ||||
-rw-r--r-- | site/features/step_definitions/within_steps.rb | 1 | ||||
-rw-r--r-- | site/spec/factories.rb | 5 | ||||
-rw-r--r-- | site/spec/models/agenda_spec.rb | 22 | ||||
-rw-r--r-- | site/spec/models/approval_spec.rb | 36 |
12 files changed, 177 insertions, 2 deletions
diff --git a/site/app/controllers/approvals_controller.rb b/site/app/controllers/approvals_controller.rb new file mode 100644 index 0000000..aeead3b --- /dev/null +++ b/site/app/controllers/approvals_controller.rb @@ -0,0 +1,7 @@ +class ApprovalsController < ApplicationController + + hobo_model_controller + + auto_actions :all, :except => [:new, :index] + +end diff --git a/site/app/models/agenda.rb b/site/app/models/agenda.rb index bf38838..75a9a23 100644 --- a/site/app/models/agenda.rb +++ b/site/app/models/agenda.rb @@ -13,6 +13,7 @@ class Agenda < ActiveRecord::Base has_many :agenda_items has_many :participations has_many :proxies + has_many :approvals lifecycle do state :open, :default => true @@ -45,7 +46,16 @@ class Agenda < ActiveRecord::Base end def view_permitted?(field) - true + return true unless field == :summary + return true if approvals.count >= 4 + return true if acting_user.council_member? + false + end + + after_update do |agenda| + if agenda.summary_changed? + agenda.approvals.each { |approval| approval.destroy } + end end before_create do |agenda| diff --git a/site/app/models/approval.rb b/site/app/models/approval.rb new file mode 100644 index 0000000..d36232c --- /dev/null +++ b/site/app/models/approval.rb @@ -0,0 +1,27 @@ +require 'permissions/set.rb' + +class Approval < ActiveRecord::Base + + hobo_model # Don't put anything above this + + fields do + timestamps + end + + belongs_to :user, :null => false + belongs_to :agenda, :null => false + + validates_presence_of :user_id + validates_presence_of :agenda_id + validates_uniqueness_of :user_id, :scope => :agenda_id + + def view_permitted?(field) + true + end + + multi_permission(:create, :destroy, :update) do + return false unless user_is?(acting_user) + return false unless acting_user.council_member? + true + end +end diff --git a/site/app/views/agendas/show.dryml b/site/app/views/agendas/show.dryml index 40a413e..0471eb4 100644 --- a/site/app/views/agendas/show.dryml +++ b/site/app/views/agendas/show.dryml @@ -13,5 +13,21 @@ <a href="&send(this.second)"><view:first/></a> </collection> </div> + <if test="¤t_user.council_member? and not this.summary.nil? and not this.summary.empty?"> + <form action="&create_approval_path" if="&Approval.user_is(current_user).agenda_is(this).count.zero?"> + <input type="hidden" name="approval[user_id]" value="¤t_user.id"/> + <input type="hidden" name="approval[agenda_id]" value="&this.id"/> + <submit label="approve summary"/> + </form> + <else> + <with with="&Approval.agenda_is(this).user_is(current_user).first"> + <delete-button label="remove your approval for this summary" /> + </with> + </else> + </if> + <unless test="&this.approvals.count.zero?"> + Summary for this agenda was approved by <%= this.approvals.count %> council member(s): + <%= this.approvals.*.user.*.name.join(", ") %>. + </unless> </append-content-body:> </show-page> diff --git a/site/config/hobo_routes.rb b/site/config/hobo_routes.rb index a426e53..97dced8 100644 --- a/site/config/hobo_routes.rb +++ b/site/config/hobo_routes.rb @@ -15,6 +15,14 @@ Council::Application.routes.draw do delete 'proxies/:id(.:format)' => 'proxies#destroy', :as => 'destroy_proxy', :constraints => { :id => %r([^/.?]+) } + # Resource routes for controller "approvals" + get 'approvals/:id/edit(.:format)' => 'approvals#edit', :as => 'edit_approval' + get 'approvals/:id(.:format)' => 'approvals#show', :as => 'approval', :constraints => { :id => %r([^/.?]+) } + post 'approvals(.:format)' => 'approvals#create', :as => 'create_approval' + put 'approvals/:id(.:format)' => 'approvals#update', :as => 'update_approval', :constraints => { :id => %r([^/.?]+) } + delete 'approvals/:id(.:format)' => 'approvals#destroy', :as => 'destroy_approval', :constraints => { :id => %r([^/.?]+) } + + # Lifecycle routes for controller "users" post 'users/signup(.:format)' => 'users#do_signup', :as => 'do_user_signup' get 'users/signup(.:format)' => 'users#signup', :as => 'user_signup' diff --git a/site/db/schema.rb b/site/db/schema.rb index a6232e1..48027f5 100644 --- a/site/db/schema.rb +++ b/site/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20110721103758) do +ActiveRecord::Schema.define(:version => 20110721195225) do create_table "agenda_items", :force => true do |t| t.string "title", :default => "", :null => false @@ -41,6 +41,16 @@ ActiveRecord::Schema.define(:version => 20110721103758) do add_index "agendas", ["state"], :name => "index_agendas_on_state" + create_table "approvals", :force => true do |t| + t.datetime "created_at" + t.datetime "updated_at" + t.integer "user_id", :null => false + t.integer "agenda_id", :null => false + end + + add_index "approvals", ["agenda_id"], :name => "index_approvals_on_agenda_id" + add_index "approvals", ["user_id"], :name => "index_approvals_on_user_id" + create_table "delayed_jobs", :force => true do |t| t.integer "priority", :default => 0 t.integer "attempts", :default => 0 diff --git a/site/features/meeting_summary_approvals.feature b/site/features/meeting_summary_approvals.feature new file mode 100644 index 0000000..e49e467 --- /dev/null +++ b/site/features/meeting_summary_approvals.feature @@ -0,0 +1,28 @@ +Feature: Meeting summary approvals + As council member I want to prepare meeting summaries + And I want other council members to approve them + So they will become public only when majority of council approves + + Scenario: Write meeting summary + Given I am logged in as a council member + When I am on the current agenda page + And I follow "Edit" + And I fill in "agenda[summary]" with "some summary" + And I press "Save" + Then I should see "some summary" as summary + + Scenario: Approve meeting summary, then remove approval + Given I am logged in as a council member + When current agenda has a summary + And I am on the current agenda page + And I press "approve summary" + Then I should see "The Approval was created successfully" in the notices + + When I am on the current agenda page + Then I should see "Summary for this agenda was approved by 1 council member(s): Example." + + When I press "remove your approval for this summary" + And I confirm + + When I am on the current agenda page + Then I should not see "Summary for this agenda was approved" diff --git a/site/features/step_definitions/meeting_summary_approvals_steps.rb b/site/features/step_definitions/meeting_summary_approvals_steps.rb new file mode 100644 index 0000000..adf1481 --- /dev/null +++ b/site/features/step_definitions/meeting_summary_approvals_steps.rb @@ -0,0 +1,5 @@ +When /^current agenda has a summary$/ do + agenda = Agenda.current + agenda.summary = 'Summary' + agenda.save! +end diff --git a/site/features/step_definitions/within_steps.rb b/site/features/step_definitions/within_steps.rb index a36a4af..42f2ff6 100644 --- a/site/features/step_definitions/within_steps.rb +++ b/site/features/step_definitions/within_steps.rb @@ -11,6 +11,7 @@ 'as meeting time' => '.meeting-time-view', 'as proxy' => '.collection.proxies.proxies-collection', 'as the user nick' => '.user-irc-nick', + 'as summary' => '.agenda-summary', 'as voting option' => '.collection.voting-options', 'as voting option description' => '.voting-option-description' }. diff --git a/site/spec/factories.rb b/site/spec/factories.rb index 01a69f7..2664917 100644 --- a/site/spec/factories.rb +++ b/site/spec/factories.rb @@ -32,4 +32,9 @@ Factory.define :proxy do |p|; p.agenda {Factory(:agenda)} end +Factory.define :approval do |a|; + a.user {users_factory(:council)} + a.agenda {Agenda.current} +end + require File.expand_path("../support/users_factory.rb", __FILE__) diff --git a/site/spec/models/agenda_spec.rb b/site/spec/models/agenda_spec.rb index 00165d1..b9e564c 100644 --- a/site/spec/models/agenda_spec.rb +++ b/site/spec/models/agenda_spec.rb @@ -23,6 +23,20 @@ describe Agenda do end end + it 'should allow everybody to view summaries after 4 council members approved it' do + agenda = Agenda.current + + for u in users_factory(:guest, :user, :admin) + agenda.should_not be_viewable_by(u, :summary) + end + + (1..4).each { |i| Factory(:approval, :agenda => agenda) } + + for u in users_factory(AllRoles) + agenda.should be_viewable_by(u, :summary) + end + end + it 'should allow only administrators and council members to edit and update' do a = Factory(:agenda) for u in users_factory(:guest, :user) @@ -310,4 +324,12 @@ describe Agenda do VotingOption.last.description.should == 'new option' end end + + it 'should remove approvals for summary, when summary changes' do + agenda = Agenda.current + Factory(:approval, :agenda => agenda) + agenda.summary = 'changed' + agenda.save! + Approval.count.should be_zero + end end diff --git a/site/spec/models/approval_spec.rb b/site/spec/models/approval_spec.rb new file mode 100644 index 0000000..4057a6d --- /dev/null +++ b/site/spec/models/approval_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Approval do + it 'should be viewable by everybody' do + approval = Factory(:approval) + for user in users_factory(AllRoles) + approval.should be_viewable_by(user) + end + end + + it 'only council members should be able to change it - and only for themselves' do + for user in users_factory(:council, :council_admin) + approval = Factory(:approval, :user => user) + approval.should be_creatable_by(user) + approval.should be_editable_by(user) + approval.should be_updatable_by(user) + approval.should be_destroyable_by(user) + end + + approval = Factory(:approval) + for user in users_factory(:council, :council_admin) + approval.should_not be_creatable_by(user) + approval.should_not be_editable_by(user) + approval.should_not be_updatable_by(user) + approval.should_not be_destroyable_by(user) + end + + for user in users_factory(:user, :admin) + approval = Approval.new :user => user, :agenda => Agenda.current + approval.should_not be_creatable_by(user) + approval.should_not be_editable_by(user) + approval.should_not be_updatable_by(user) + approval.should_not be_destroyable_by(user) + end + end +end |