adhocracy 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.rdoc +183 -2
- data/app/models/adhocracy/membership.rb +1 -1
- data/app/models/adhocracy/membership_invitation.rb +1 -23
- data/app/models/adhocracy/membership_request.rb +1 -23
- data/config/locales/en.yml +3 -1
- data/db/migrate/20140306214416_create_adhocracy_memberships.rb +2 -0
- data/lib/adhocracy/acts_as_group.rb +26 -0
- data/lib/adhocracy/joinable.rb +71 -0
- data/lib/adhocracy/version.rb +1 -1
- data/lib/adhocracy.rb +1 -0
- data/spec/dummy/db/schema.rb +2 -0
- data/spec/lib/adhocracy/acts_as_group_spec.rb +75 -1
- data/spec/lib/adhocracy/acts_as_member_spec.rb +6 -0
- data/spec/spec_helper.rb +3 -0
- metadata +49 -34
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MGIyMWQyYTE2OGZmM2MzMDRhNmJkYzYyZDcwMGM3ZWQzMDBkZDNjMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjdhYWMwMTNlYmE2YzYzNDYyNGQ3MTE3ZWRhY2RkMmYyYjczNzNlNA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MmYwZjA2ZDYxNzcwOTFmZDE3NDQzYWM2MWNkMjM2MTg1ODUxYjhkMGQyOTBm
|
10
|
+
OWUwODM3ZmE0MzNjNzllZjE5ZDQ3MWFkYTA1MmM2NzgwMTAzY2ExYzc5YmZi
|
11
|
+
ZTEzOGE0YmQ4YzU2ZDIyYWM4ZWYwMDQ5MjgyZWJmZTNhM2Q2NGU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTdkYjk0MGJmNzRiN2VjNmI1ZGUyMGI1NTVkZTE2NzE2OTliNDBjZTNiOWY4
|
14
|
+
NmNmNGE4ZDFmOTQ2MzFiNGNhMzQzZjRiODk4NzFhZmJkZjEwOTdmNjA1NDg3
|
15
|
+
NTU4YTg3MDZhYjUzODU2OTg1MTY5ZDAwOWMzOGUxNmI4OGUyZTg=
|
data/README.rdoc
CHANGED
@@ -1,3 +1,184 @@
|
|
1
|
-
= Adhocracy {<img src="https://badge.fury.io/rb/adhocracy.png" alt="Gem Version" />}[http://badge.fury.io/rb/adhocracy] {<img src="https://travis-ci.org/timothycommoner/adhocracy.png?branch=master" alt="Build Status" />}[https://travis-ci.org/timothycommoner/adhocracy] {<img src="https://codeclimate.com/github/timothycommoner/adhocracy.png" />}[https://codeclimate.com/github/timothycommoner/adhocracy]
|
1
|
+
= Adhocracy {<img src="https://badge.fury.io/rb/adhocracy.png" alt="Gem Version" />}[http://badge.fury.io/rb/adhocracy] {<img src="https://travis-ci.org/timothycommoner/adhocracy.png?branch=master" alt="Build Status" />}[https://travis-ci.org/timothycommoner/adhocracy] {<img src="https://coveralls.io/repos/timothycommoner/adhocracy/badge.png" alt="Coverage Status" />}[https://coveralls.io/r/timothycommoner/adhocracy] {<img src="https://codeclimate.com/github/timothycommoner/adhocracy.png" />}[https://codeclimate.com/github/timothycommoner/adhocracy]
|
2
2
|
|
3
|
-
A group management engine for Rails.
|
3
|
+
A group management engine for Rails.
|
4
|
+
|
5
|
+
== Compatibility
|
6
|
+
|
7
|
+
Adhocracy is a Rails Engine, which means it plays best with Rails applications. So far, it's only been tested with Rails 4.
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
=== Installation
|
12
|
+
|
13
|
+
1. Add Adhocracy to your gemfile: `gem 'adhocracy'`
|
14
|
+
2. Run bundler: `bundle install`
|
15
|
+
3. Run this in your app folder: `rake adhocracy:install:migrations`
|
16
|
+
4. Run your migrations: `rake db:migrate`
|
17
|
+
5. Add `acts_as_group` to the models you want to have group functionality
|
18
|
+
6. Add `acts_as_member` to the models you want to have member functionality
|
19
|
+
|
20
|
+
=== Creating Groups and Members
|
21
|
+
|
22
|
+
Scenario: You want your Club model to have group functionality. Ideally, it'll accept members from both the Student and Teacher model.
|
23
|
+
|
24
|
+
First, add `acts_as_group` to your Club model:
|
25
|
+
|
26
|
+
class Club < ActiveRecord::Base
|
27
|
+
acts_as_group
|
28
|
+
end
|
29
|
+
|
30
|
+
Then, add 'acts_as_member' to your Student and Teacher models:
|
31
|
+
|
32
|
+
class Student < ActiveRecord::Base
|
33
|
+
acts_as_member
|
34
|
+
end
|
35
|
+
|
36
|
+
class Teacher < ActiveRecord::Base
|
37
|
+
acts_as_member
|
38
|
+
end
|
39
|
+
|
40
|
+
After that, you can add members to your Club by:
|
41
|
+
|
42
|
+
@club.add_member(@student)
|
43
|
+
@student.join_group(@club)
|
44
|
+
@teacher.join_group(@club)
|
45
|
+
|
46
|
+
List the current members:
|
47
|
+
|
48
|
+
@club.members # => returns an array with @student and @teacher in it
|
49
|
+
|
50
|
+
Or list the groups a member is a part of:
|
51
|
+
|
52
|
+
@student.groups # => returns an array with only @club
|
53
|
+
|
54
|
+
Check for membership:
|
55
|
+
|
56
|
+
@student.member_of?(@club) # => true
|
57
|
+
@club.has_member?(@teacher) # => true
|
58
|
+
|
59
|
+
And destroy memberships
|
60
|
+
|
61
|
+
@student.leave_group(@club)
|
62
|
+
@group.remove_member(@teacher)
|
63
|
+
|
64
|
+
=== Officers
|
65
|
+
|
66
|
+
Scenario: You want a special class of membership that has the privilege to edit the group and accept/invite new members.
|
67
|
+
|
68
|
+
Adhocracy allows for administrative members called officers. You can create a new officer with:
|
69
|
+
|
70
|
+
@club.add_officer(@student)
|
71
|
+
|
72
|
+
Alternatively, if `@student` is already a member, you can promote her with:
|
73
|
+
|
74
|
+
@club.promote_to_officer(@student)
|
75
|
+
|
76
|
+
Later, you can strip an officer of her title with:
|
77
|
+
|
78
|
+
@club.demote_officer(@student)
|
79
|
+
|
80
|
+
=== Inviting Members
|
81
|
+
|
82
|
+
Scenario: You want your users to have control over which groups they join.
|
83
|
+
|
84
|
+
Groups can send invitations to users:
|
85
|
+
|
86
|
+
@club.invite_member(@student)
|
87
|
+
@student.groups # => does not yet include @club
|
88
|
+
@student.group_invitations # => array including @club
|
89
|
+
|
90
|
+
The user can either accept or decline:
|
91
|
+
|
92
|
+
@invitation = @student.membership_invitations.first
|
93
|
+
@invitation.accept
|
94
|
+
- or -
|
95
|
+
@invitation.decline
|
96
|
+
|
97
|
+
If they accept, then they become a member of the group.
|
98
|
+
|
99
|
+
Invitations can be queried for their state of acceptance:
|
100
|
+
|
101
|
+
@invitation.pending?
|
102
|
+
@invitation.accepted?
|
103
|
+
@invitation.declined?
|
104
|
+
|
105
|
+
You can also check to see if an invitation is already sent:
|
106
|
+
|
107
|
+
@student.invited_to?(@club)
|
108
|
+
@club.invited?(@student)
|
109
|
+
|
110
|
+
These checks can include the state of the invitation:
|
111
|
+
|
112
|
+
@student.invited_to?(@club, { pending: true })
|
113
|
+
@student.invited_to?(@club, { accepted: false })
|
114
|
+
@student.invited_to?(@club, { declined: false })
|
115
|
+
|
116
|
+
=== Requesting Membership
|
117
|
+
|
118
|
+
Scenario: You want your groups to have control over which users join them.
|
119
|
+
|
120
|
+
Interested users can send membership requests to groups:
|
121
|
+
|
122
|
+
@student.request_membership_in(@club)
|
123
|
+
@club.members # => does not yet include @student
|
124
|
+
@club.membership_requests # => array including @student
|
125
|
+
|
126
|
+
The group can either accept or decline:
|
127
|
+
|
128
|
+
@request = @club.membership_requests.first
|
129
|
+
@request.accept
|
130
|
+
- or -
|
131
|
+
@request.decline
|
132
|
+
|
133
|
+
Requests can be queried for their state of acceptance:
|
134
|
+
|
135
|
+
@request.pending?
|
136
|
+
@request.accepted?
|
137
|
+
@request.declined?
|
138
|
+
|
139
|
+
You can also check to see if a request is already sent:
|
140
|
+
|
141
|
+
@student.requested_membership_in?(@club)
|
142
|
+
@club.recieved_request_from?(@student)
|
143
|
+
|
144
|
+
These checks can include the state of the request:
|
145
|
+
|
146
|
+
@student.requested_membership_in?(@club, { pending: true })
|
147
|
+
@student.requested_membership_in?(@club, { accepted: false })
|
148
|
+
@student.requested_membership_in?(@club, { declined: false })
|
149
|
+
|
150
|
+
=== Nesting Groups
|
151
|
+
|
152
|
+
Scenario: You want your Company model to have many subsidiary companies.
|
153
|
+
|
154
|
+
Create a model that both `acts_as_group` and `acts_as_member`:
|
155
|
+
|
156
|
+
class Company < ActiveRecord::Base
|
157
|
+
acts_as_group
|
158
|
+
acts_as_member
|
159
|
+
end
|
160
|
+
|
161
|
+
You can then nest companies like you would any other member:
|
162
|
+
|
163
|
+
@company.add_member(@child_company)
|
164
|
+
@child_company.add_member(@grand_child_company)
|
165
|
+
|
166
|
+
== Limitations
|
167
|
+
|
168
|
+
Unfortunately, Rails does not support `has_many through` relationships that pass through a polymorphic join table, which we do in Adhocracy. In order to work around this limitation, we've created pseudo-associations, such as `@club.members` and `@user.groups`. These pseudo-associations return a simple array, rather than the feature-packed associations Rails typically uses. This means you can't chain in scopes or use commands like `@user.groups.create`. If you know of a way we can reincorporate Rails associations without losing our ability to join groups and members polymorphically, please share your thoughts!
|
169
|
+
|
170
|
+
== Issues
|
171
|
+
|
172
|
+
Adhocracy is still very young, and both its functionality and its documentation are bound to be lacking. If you're having trouble with something, feel free to open an issue.
|
173
|
+
|
174
|
+
== Contributing
|
175
|
+
|
176
|
+
Feel free to send us a pull request. Public methods, callbacks, and validations should have Rspec tests to back them up.
|
177
|
+
|
178
|
+
=== Contributors
|
179
|
+
|
180
|
+
Timothy Baron
|
181
|
+
|
182
|
+
== License
|
183
|
+
|
184
|
+
Released under the MIT license.
|
@@ -1,31 +1,9 @@
|
|
1
1
|
module Adhocracy
|
2
2
|
class MembershipInvitation < ActiveRecord::Base
|
3
3
|
include Acceptable
|
4
|
+
include Joinable
|
4
5
|
|
5
6
|
belongs_to :member, polymorphic: true
|
6
7
|
belongs_to :group, polymorphic: true
|
7
|
-
|
8
|
-
validate :no_pending_invitations, on: :create
|
9
|
-
validate :no_declined_invitations, on: :create
|
10
|
-
validate :not_currently_a_member, on: :create
|
11
|
-
|
12
|
-
private
|
13
|
-
def no_pending_invitations
|
14
|
-
if self.member.invited_to?(self.group, { pending: true })
|
15
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_invitation.still_pending")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def no_declined_invitations
|
20
|
-
if self.member.invited_to?(self.group, { declined: true })
|
21
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_invitation.already_declined")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def not_currently_a_member
|
26
|
-
if self.member.member_of?(self.group)
|
27
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_invitation.already_a_member")
|
28
|
-
end
|
29
|
-
end
|
30
8
|
end
|
31
9
|
end
|
@@ -1,31 +1,9 @@
|
|
1
1
|
module Adhocracy
|
2
2
|
class MembershipRequest < ActiveRecord::Base
|
3
3
|
include Acceptable
|
4
|
+
include Joinable
|
4
5
|
|
5
6
|
belongs_to :member, polymorphic: true
|
6
7
|
belongs_to :group, polymorphic: true
|
7
|
-
|
8
|
-
validate :no_pending_requests, on: :create
|
9
|
-
validate :no_declined_requests, on: :create
|
10
|
-
validate :not_currently_a_member, on: :create
|
11
|
-
|
12
|
-
private
|
13
|
-
def no_pending_requests
|
14
|
-
if self.member.requested_membership_in?(self.group, { pending: true })
|
15
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_request.still_pending")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def no_declined_requests
|
20
|
-
if self.member.requested_membership_in?(self.group, { declined: true })
|
21
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_request.already_declined")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def not_currently_a_member
|
26
|
-
if self.member.member_of?(self.group)
|
27
|
-
errors[:base] << I18n.t("activerecord.errors.models.membership_request.already_a_member")
|
28
|
-
end
|
29
|
-
end
|
30
8
|
end
|
31
9
|
end
|
data/config/locales/en.yml
CHANGED
@@ -8,7 +8,9 @@ en:
|
|
8
8
|
still_pending: "Invitation still pending."
|
9
9
|
already_declined: "Cannot invite member again."
|
10
10
|
already_a_member: "Already a member."
|
11
|
+
other_party_had_pending_request: "The member already sent a request. Membership automatically accepted."
|
11
12
|
membership_request:
|
12
13
|
still_pending: "Request still pending."
|
13
14
|
already_declined: "Cannot request membership again."
|
14
|
-
already_a_member: "Already a member."
|
15
|
+
already_a_member: "Already a member."
|
16
|
+
other_party_had_pending_request: "The group already sent an invitation. Membership automatically accepted."
|
@@ -5,10 +5,12 @@ class CreateAdhocracyMemberships < ActiveRecord::Migration
|
|
5
5
|
t.integer :member_id
|
6
6
|
t.string :group_type
|
7
7
|
t.integer :group_id
|
8
|
+
t.boolean :officer, null: false, default: false
|
8
9
|
|
9
10
|
t.timestamps
|
10
11
|
end
|
11
12
|
|
13
|
+
add_index :adhocracy_memberships, :officer
|
12
14
|
add_index :adhocracy_memberships,
|
13
15
|
[:member_id, :member_type],
|
14
16
|
name: "adhocracy_memberships_on_member"
|
@@ -10,6 +10,8 @@ module Adhocracy
|
|
10
10
|
class_name: "Adhocracy::MembershipInvitation"
|
11
11
|
has_many :membership_requests, as: :group,
|
12
12
|
class_name: "Adhocracy::MembershipRequest"
|
13
|
+
has_many :officer_memberships, -> { where officer: true }, as: :group,
|
14
|
+
class_name: "Adhocracy::Membership"
|
13
15
|
|
14
16
|
send :include, InstanceMethods
|
15
17
|
end
|
@@ -20,6 +22,11 @@ module Adhocracy
|
|
20
22
|
MembershipAssociation.new(group: self).list_members_for_membership
|
21
23
|
end
|
22
24
|
|
25
|
+
def officers
|
26
|
+
Adhocracy::Membership.where(group: self, officer: true).
|
27
|
+
includes(:member).collect { |membership| membership.member }
|
28
|
+
end
|
29
|
+
|
23
30
|
def invited_members
|
24
31
|
MembershipAssociation.new(group: self).
|
25
32
|
list_members_for_membership_invitation
|
@@ -35,6 +42,25 @@ module Adhocracy
|
|
35
42
|
create_membership
|
36
43
|
end
|
37
44
|
|
45
|
+
def add_officer(member)
|
46
|
+
membership = Adhocracy::Membership.where(member: member, group: self).
|
47
|
+
first_or_create(officer: true)
|
48
|
+
promote_to_officer(member, membership) unless membership.officer?
|
49
|
+
membership
|
50
|
+
end
|
51
|
+
|
52
|
+
def promote_to_officer(member, membership = nil)
|
53
|
+
membership ||= Adhocracy::Membership.find_by(member: member, group: self)
|
54
|
+
return false if !membership.present? || membership.officer?
|
55
|
+
return membership.update_column(:officer, true)
|
56
|
+
end
|
57
|
+
|
58
|
+
def demote_officer(member)
|
59
|
+
membership = Adhocracy::Membership.find_by(member: member, group: self)
|
60
|
+
return false if !membership.present? || !membership.officer?
|
61
|
+
return membership.update_column(:officer, false)
|
62
|
+
end
|
63
|
+
|
38
64
|
def invite_member(member)
|
39
65
|
MembershipAssociation.new(member: member, group: self).
|
40
66
|
create_membership_invitation
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Adhocracy
|
2
|
+
module Joinable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
validate :no_pending_joins, on: :create
|
7
|
+
validate :no_declined_joins, on: :create
|
8
|
+
validate :not_currently_a_member, on: :create
|
9
|
+
validate :other_party_has_pending_request, on: :create
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def detect_preexisting_join(state, inverted = false)
|
14
|
+
self.member.send(query_symbol(inverted), self.group, { state => true })
|
15
|
+
end
|
16
|
+
|
17
|
+
def no_pending_joins
|
18
|
+
if detect_preexisting_join(:pending)
|
19
|
+
errors[:base] << I18n.t("activerecord.errors.models.membership_#{i18n_string}.still_pending")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def no_declined_joins
|
24
|
+
if detect_preexisting_join(:declined)
|
25
|
+
errors[:base] << I18n.t("activerecord.errors.models.membership_#{i18n_string}.already_declined")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def not_currently_a_member
|
30
|
+
if self.member.member_of?(self.group)
|
31
|
+
errors[:base] << I18n.t("activerecord.errors.models.membership_#{i18n_string}.already_a_member")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def other_party_has_pending_request
|
36
|
+
if detect_preexisting_join(:pending, true)
|
37
|
+
accept_preexisting_join
|
38
|
+
errors[:base] << I18n.t("activerecord.errors.models.membership_#{i18n_string}.other_party_had_pending_request")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def i18n_string
|
43
|
+
return case self.class.name
|
44
|
+
when "Adhocracy::MembershipInvitation" then "invitation"
|
45
|
+
when "Adhocracy::MembershipRequest" then "request"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def query_symbol(inverted)
|
50
|
+
test_class = inverted == false ? self.class.name : inverted_class
|
51
|
+
return case test_class
|
52
|
+
when "Adhocracy::MembershipInvitation" then :invited_to?
|
53
|
+
when "Adhocracy::MembershipRequest" then :requested_membership_in?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def inverted_class
|
58
|
+
return case self.class.name
|
59
|
+
when "Adhocracy::MembershipInvitation"
|
60
|
+
"Adhocracy::MembershipRequest"
|
61
|
+
when "Adhocracy::MembershipRequest"
|
62
|
+
"Adhocracy::MembershipInvitation"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def accept_preexisting_join
|
67
|
+
inverted_class.constantize.where(member: self.member, group: self.group).
|
68
|
+
first.accept
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/adhocracy/version.rb
CHANGED
data/lib/adhocracy.rb
CHANGED
data/spec/dummy/db/schema.rb
CHANGED
@@ -49,6 +49,7 @@ ActiveRecord::Schema.define(version: 20140306214620) do
|
|
49
49
|
t.integer "member_id"
|
50
50
|
t.string "group_type"
|
51
51
|
t.integer "group_id"
|
52
|
+
t.boolean "officer", default: false, null: false
|
52
53
|
t.datetime "created_at"
|
53
54
|
t.datetime "updated_at"
|
54
55
|
end
|
@@ -57,6 +58,7 @@ ActiveRecord::Schema.define(version: 20140306214620) do
|
|
57
58
|
add_index "adhocracy_memberships", ["group_id", "group_type"], name: "adhocracy_membership_requests_on_group", using: :btree
|
58
59
|
add_index "adhocracy_memberships", ["group_id", "group_type"], name: "adhocracy_memberships_on_group", using: :btree
|
59
60
|
add_index "adhocracy_memberships", ["member_id", "member_type"], name: "adhocracy_memberships_on_member", using: :btree
|
61
|
+
add_index "adhocracy_memberships", ["officer"], name: "index_adhocracy_memberships_on_officer", using: :btree
|
60
62
|
|
61
63
|
create_table "adhocs", force: true do |t|
|
62
64
|
end
|
@@ -19,6 +19,10 @@ module Adhocracy
|
|
19
19
|
it "membership invitations" do
|
20
20
|
expect(@adhoc).to have_many(:membership_invitations)
|
21
21
|
end
|
22
|
+
|
23
|
+
it "officer memberships" do
|
24
|
+
expect(@adhoc).to have_many(:officer_memberships)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
context "produces a list" do
|
@@ -30,7 +34,7 @@ module Adhocracy
|
|
30
34
|
@user4 = FactoryGirl.create(:user)
|
31
35
|
@user5 = FactoryGirl.create(:user)
|
32
36
|
@adhoc.add_member(@user1)
|
33
|
-
@adhoc.
|
37
|
+
@adhoc.add_officer(@user3)
|
34
38
|
@adhoc.invite_member(@user4)
|
35
39
|
@user5.request_membership_in(@adhoc)
|
36
40
|
end
|
@@ -43,6 +47,14 @@ module Adhocracy
|
|
43
47
|
expect(@adhoc.members).to_not include @user2, @user4, @user5
|
44
48
|
end
|
45
49
|
|
50
|
+
it "including all officers" do
|
51
|
+
expect(@adhoc.officers).to include @user3
|
52
|
+
end
|
53
|
+
|
54
|
+
it "excluding non-officers" do
|
55
|
+
expect(@adhoc.officers).to_not include @user1, @user2, @user4, @user5
|
56
|
+
end
|
57
|
+
|
46
58
|
it "including all invited members" do
|
47
59
|
expect(@adhoc.invited_members).to include @user4
|
48
60
|
end
|
@@ -136,6 +148,16 @@ module Adhocracy
|
|
136
148
|
expect(@adhoc.add_member(@user).valid?).to be false
|
137
149
|
end
|
138
150
|
|
151
|
+
it "creating officers" do
|
152
|
+
@adhoc.add_officer(@user)
|
153
|
+
expect(@adhoc.officers).to include @user
|
154
|
+
end
|
155
|
+
|
156
|
+
it "not creating duplicate officers" do
|
157
|
+
@adhoc.add_officer(@user)
|
158
|
+
expect(@adhoc.add_officer(@user).valid?).to be false
|
159
|
+
end
|
160
|
+
|
139
161
|
it "inviting members" do
|
140
162
|
@adhoc.invite_member(@user)
|
141
163
|
expect(@adhoc.invited_members).to include @user
|
@@ -156,6 +178,12 @@ module Adhocracy
|
|
156
178
|
@adhoc.add_member(@user)
|
157
179
|
expect(@adhoc.invite_member(@user).valid?).to be false
|
158
180
|
end
|
181
|
+
|
182
|
+
it "accepting invited members if they've requested membership" do
|
183
|
+
@user.request_membership_in(@adhoc)
|
184
|
+
expect(@adhoc.invite_member(@user).valid?).to be false
|
185
|
+
expect(@adhoc.members).to include @user
|
186
|
+
end
|
159
187
|
end
|
160
188
|
|
161
189
|
context "destroys memberships" do
|
@@ -175,5 +203,51 @@ module Adhocracy
|
|
175
203
|
end
|
176
204
|
end
|
177
205
|
|
206
|
+
context "promotes members to officers" do
|
207
|
+
before :each do
|
208
|
+
@adhoc = FactoryGirl.create(:adhoc)
|
209
|
+
@user = FactoryGirl.create(:user)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "if the member is a non-officer" do
|
213
|
+
@adhoc.add_member(@user)
|
214
|
+
@adhoc.promote_to_officer(@user)
|
215
|
+
expect(@adhoc.officers).to include @user
|
216
|
+
end
|
217
|
+
|
218
|
+
it "if the member is a non-officer member (and add_officer is used)" do
|
219
|
+
@adhoc.add_member(@user)
|
220
|
+
@adhoc.add_officer(@user)
|
221
|
+
expect(@adhoc.officers).to include @user
|
222
|
+
end
|
223
|
+
|
224
|
+
it "but returns false if the user is not a member" do
|
225
|
+
expect(@adhoc.promote_to_officer(@user)).to be false
|
226
|
+
end
|
227
|
+
|
228
|
+
it "but returns false if the member is already an officer" do
|
229
|
+
@adhoc.add_officer(@user)
|
230
|
+
expect(@adhoc.promote_to_officer(@user)).to be false
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
context "demotes officers" do
|
235
|
+
before :each do
|
236
|
+
@adhoc = FactoryGirl.create(:adhoc)
|
237
|
+
@user = FactoryGirl.create(:user)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "if the member is an officer" do
|
241
|
+
@adhoc.add_officer(@user)
|
242
|
+
@adhoc.demote_officer(@user)
|
243
|
+
expect(@adhoc.officers).to_not include @user
|
244
|
+
end
|
245
|
+
|
246
|
+
it "but returns false if the member is not an officer" do
|
247
|
+
@adhoc.add_member(@user)
|
248
|
+
expect(@adhoc.demote_officer(@user)).to be false
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
178
252
|
end
|
179
253
|
end
|
@@ -118,6 +118,12 @@ module Adhocracy
|
|
118
118
|
expect(@user.requested_membership_in?(@adhoc, { pending: true })).
|
119
119
|
to be false
|
120
120
|
end
|
121
|
+
|
122
|
+
it "accepting requested groups if they've already invited membership" do
|
123
|
+
@adhoc.invite_member(@user)
|
124
|
+
expect(@user.request_membership_in(@adhoc).valid?).to be false
|
125
|
+
expect(@user.groups).to include @adhoc
|
126
|
+
end
|
121
127
|
end
|
122
128
|
|
123
129
|
context "handles prospective groups by" do
|
data/spec/spec_helper.rb
CHANGED
@@ -10,6 +10,9 @@ Spork.prefork do
|
|
10
10
|
require 'database_cleaner'
|
11
11
|
require 'shoulda'
|
12
12
|
require 'debugger'
|
13
|
+
require 'coveralls'
|
14
|
+
|
15
|
+
Coveralls.wear!('rails')
|
13
16
|
|
14
17
|
# Requires supporting ruby files with custom matchers and macros, etc,
|
15
18
|
# in spec/support/ and its subdirectories.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adhocracy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- timothycommoner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ! '>='
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: coveralls
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
description: Adhocracy is group management engine for Rails.
|
140
154
|
email:
|
141
155
|
- timothythehuman@gmail.com
|
@@ -164,6 +178,7 @@ files:
|
|
164
178
|
- lib/adhocracy/acts_as_group.rb
|
165
179
|
- lib/adhocracy/acts_as_member.rb
|
166
180
|
- lib/adhocracy/engine.rb
|
181
|
+
- lib/adhocracy/joinable.rb
|
167
182
|
- lib/adhocracy/membership_association.rb
|
168
183
|
- lib/adhocracy/version.rb
|
169
184
|
- lib/tasks/adhocracy_tasks.rake
|
@@ -240,48 +255,48 @@ summary: Adhocracy is group management engine for Rails.
|
|
240
255
|
test_files:
|
241
256
|
- spec/lib/adhocracy/acts_as_group_spec.rb
|
242
257
|
- spec/lib/adhocracy/acts_as_member_spec.rb
|
243
|
-
- spec/
|
244
|
-
- spec/factories/adhoc.rb
|
245
|
-
- spec/factories/adhocracy_membership_invitations.rb
|
246
|
-
- spec/factories/users.rb
|
247
|
-
- spec/factories/adhocracy_membership_requests.rb
|
248
|
-
- spec/spec_helper.rb
|
249
|
-
- spec/dummy/Rakefile
|
250
|
-
- spec/dummy/config/application.rb
|
251
|
-
- spec/dummy/config/boot.rb
|
252
|
-
- spec/dummy/config/initializers/backtrace_silencers.rb
|
253
|
-
- spec/dummy/config/initializers/inflections.rb
|
254
|
-
- spec/dummy/config/initializers/session_store.rb
|
255
|
-
- spec/dummy/config/initializers/mime_types.rb
|
256
|
-
- spec/dummy/config/initializers/secret_token.rb
|
257
|
-
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
258
|
-
- spec/dummy/config/initializers/wrap_parameters.rb
|
259
|
-
- spec/dummy/config/routes.rb
|
260
|
-
- spec/dummy/config/environment.rb
|
261
|
-
- spec/dummy/config/locales/en.yml
|
262
|
-
- spec/dummy/config/database.yml
|
263
|
-
- spec/dummy/config/environments/development.rb
|
264
|
-
- spec/dummy/config/environments/production.rb
|
265
|
-
- spec/dummy/config/environments/test.rb
|
266
|
-
- spec/dummy/config.ru
|
258
|
+
- spec/dummy/README.rdoc
|
267
259
|
- spec/dummy/app/helpers/application_helper.rb
|
268
260
|
- spec/dummy/app/views/layouts/application.html.erb
|
269
|
-
- spec/dummy/app/controllers/application_controller.rb
|
270
261
|
- spec/dummy/app/assets/stylesheets/application.css
|
271
262
|
- spec/dummy/app/assets/javascripts/application.js
|
272
263
|
- spec/dummy/app/models/adhoc.rb
|
273
264
|
- spec/dummy/app/models/user.rb
|
274
|
-
- spec/dummy/
|
275
|
-
- spec/dummy/
|
276
|
-
- spec/dummy/
|
265
|
+
- spec/dummy/app/controllers/application_controller.rb
|
266
|
+
- spec/dummy/db/migrate/20140306214611_create_users.rb
|
267
|
+
- spec/dummy/db/migrate/20140306214620_create_adhocs.rb
|
268
|
+
- spec/dummy/db/schema.rb
|
277
269
|
- spec/dummy/public/422.html
|
278
270
|
- spec/dummy/public/404.html
|
279
271
|
- spec/dummy/public/favicon.ico
|
280
272
|
- spec/dummy/public/500.html
|
281
|
-
- spec/dummy/
|
282
|
-
- spec/dummy/
|
283
|
-
- spec/dummy/
|
284
|
-
- spec/dummy/
|
273
|
+
- spec/dummy/Rakefile
|
274
|
+
- spec/dummy/bin/rails
|
275
|
+
- spec/dummy/bin/bundle
|
276
|
+
- spec/dummy/bin/rake
|
277
|
+
- spec/dummy/config/initializers/mime_types.rb
|
278
|
+
- spec/dummy/config/initializers/inflections.rb
|
279
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
280
|
+
- spec/dummy/config/initializers/wrap_parameters.rb
|
281
|
+
- spec/dummy/config/initializers/session_store.rb
|
282
|
+
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
283
|
+
- spec/dummy/config/initializers/secret_token.rb
|
284
|
+
- spec/dummy/config/application.rb
|
285
|
+
- spec/dummy/config/environments/test.rb
|
286
|
+
- spec/dummy/config/environments/development.rb
|
287
|
+
- spec/dummy/config/environments/production.rb
|
288
|
+
- spec/dummy/config/boot.rb
|
289
|
+
- spec/dummy/config/routes.rb
|
290
|
+
- spec/dummy/config/locales/en.yml
|
291
|
+
- spec/dummy/config/environment.rb
|
292
|
+
- spec/dummy/config/database.yml
|
293
|
+
- spec/dummy/config.ru
|
294
|
+
- spec/spec_helper.rb
|
295
|
+
- spec/factories/adhocracy_membership_requests.rb
|
296
|
+
- spec/factories/users.rb
|
297
|
+
- spec/factories/adhocracy_membership_invitations.rb
|
298
|
+
- spec/factories/adhocracy_memberships.rb
|
299
|
+
- spec/factories/adhoc.rb
|
285
300
|
- spec/models/adhocracy/membership_spec.rb
|
286
301
|
- spec/models/adhocracy/membership_request_spec.rb
|
287
302
|
- spec/models/adhocracy/membership_invitation_spec.rb
|