aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--site/app/controllers/approvals_controller.rb7
-rw-r--r--site/app/models/agenda.rb12
-rw-r--r--site/app/models/approval.rb27
-rw-r--r--site/app/views/agendas/show.dryml16
-rw-r--r--site/config/hobo_routes.rb8
-rw-r--r--site/db/schema.rb12
-rw-r--r--site/features/meeting_summary_approvals.feature28
-rw-r--r--site/features/step_definitions/meeting_summary_approvals_steps.rb5
-rw-r--r--site/features/step_definitions/within_steps.rb1
-rw-r--r--site/spec/factories.rb5
-rw-r--r--site/spec/models/agenda_spec.rb22
-rw-r--r--site/spec/models/approval_spec.rb36
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="&current_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="&current_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