group model prep for communities; refs #8598
this commit just lays down a bit of ground work for communities. it defines communities as a protected group category type for accounts which allows membership in multiple groups. it also generalizes several places where student organized groups was a special case. it also removes the restriction that group.is_public always be false. this property will be used for different visibility levels within communities. finally, it lays some groundwork for handling group requests/invitations/following. test plan: - there should be no functional changes from this commit - you should be able to run GroupCategory.communities_for(account) at the console for an account, and get a category shell for communities for that account. Change-Id: Icff3f0e7fbd4ec3c0a72cdbaa310cbd0e75d0e3e Reviewed-on: https://gerrit.instructure.com/10780 Tested-by: Jenkins <jenkins@instructure.com> Reviewed-by: Brian Palmer <brianp@instructure.com>
This commit is contained in:
parent
5b04db4372
commit
127b9b3302
|
@ -74,7 +74,7 @@ class GroupsController < ApplicationController
|
||||||
end
|
end
|
||||||
@current_conferences = @group.web_conferences.select{|c| c.active? && c.users.include?(@current_user) } rescue []
|
@current_conferences = @group.web_conferences.select{|c| c.active? && c.users.include?(@current_user) } rescue []
|
||||||
@groups = @current_user.group_memberships_for(@group.context) if @current_user
|
@groups = @current_user.group_memberships_for(@group.context) if @current_user
|
||||||
if params[:join] && @group.free_association?(@current_user)
|
if params[:join] && @group.can_join?(@current_user)
|
||||||
@group.request_user(@current_user)
|
@group.request_user(@current_user)
|
||||||
if !@group.grants_right?(@current_user, session, :read)
|
if !@group.grants_right?(@current_user, session, :read)
|
||||||
render :action => 'membership_pending'
|
render :action => 'membership_pending'
|
||||||
|
@ -85,7 +85,7 @@ class GroupsController < ApplicationController
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if params[:leave] && (@group.free_association?(@current_user) || @group.student_organized?)
|
if params[:leave] && @group.can_leave?(@current_user)
|
||||||
membership = @group.membership_for_user(@current_user)
|
membership = @group.membership_for_user(@current_user)
|
||||||
if membership
|
if membership
|
||||||
membership.destroy
|
membership.destroy
|
||||||
|
@ -334,7 +334,7 @@ class GroupsController < ApplicationController
|
||||||
@user_groups = @current_user.group_memberships_for(@context).select{|g| group_ids.include?(g.id) } if @current_user
|
@user_groups = @current_user.group_memberships_for(@context).select{|g| group_ids.include?(g.id) } if @current_user
|
||||||
@user_groups ||= []
|
@user_groups ||= []
|
||||||
|
|
||||||
@available_groups = (@groups - @user_groups).select{|g| g.free_association?(@current_user) }
|
@available_groups = (@groups - @user_groups).select{|g| g.can_join?(@current_user) }
|
||||||
if !@context.grants_right?(@current_user, session, :manage_groups)
|
if !@context.grants_right?(@current_user, session, :manage_groups)
|
||||||
@groups = @user_groups
|
@groups = @user_groups
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,8 +25,6 @@ class Group < ActiveRecord::Base
|
||||||
has_many :users, :through => :group_memberships, :conditions => ['users.workflow_state != ?', 'deleted']
|
has_many :users, :through => :group_memberships, :conditions => ['users.workflow_state != ?', 'deleted']
|
||||||
has_many :participating_group_memberships, :class_name => "GroupMembership", :conditions => ['group_memberships.workflow_state = ?', 'accepted']
|
has_many :participating_group_memberships, :class_name => "GroupMembership", :conditions => ['group_memberships.workflow_state = ?', 'accepted']
|
||||||
has_many :participating_users, :source => :user, :through => :participating_group_memberships
|
has_many :participating_users, :source => :user, :through => :participating_group_memberships
|
||||||
has_many :invited_group_memberships, :class_name => "GroupMembership", :conditions => ['group_memberships.workflow_state = ?', 'invited']
|
|
||||||
has_many :invited_users, :source => :user, :through => :invited_group_memberships
|
|
||||||
belongs_to :context, :polymorphic => true
|
belongs_to :context, :polymorphic => true
|
||||||
belongs_to :group_category
|
belongs_to :group_category
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
|
@ -86,26 +84,33 @@ class Group < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def auto_accept?(user)
|
def auto_accept?(user)
|
||||||
self.context.grants_right?(user, :participate_in_groups) &&
|
self.group_category &&
|
||||||
self.student_organized? &&
|
self.group_category.available_for?(user) &&
|
||||||
|
self.group_category.allows_multiple_memberships? &&
|
||||||
self.join_level == 'parent_context_auto_join'
|
self.join_level == 'parent_context_auto_join'
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_join_request?(user)
|
def allow_join_request?(user)
|
||||||
self.context.grants_right?(user, :participate_in_groups) &&
|
self.group_category &&
|
||||||
self.student_organized? &&
|
self.group_category.available_for?(user) &&
|
||||||
|
self.group_category.allows_multiple_memberships? &&
|
||||||
['parent_context_auto_join', 'parent_context_request'].include?(self.join_level)
|
['parent_context_auto_join', 'parent_context_request'].include?(self.join_level)
|
||||||
end
|
end
|
||||||
|
|
||||||
def allow_self_signup?(user)
|
def allow_self_signup?(user)
|
||||||
|
self.context &&
|
||||||
self.context.grants_right?(user, :participate_in_groups) &&
|
self.context.grants_right?(user, :participate_in_groups) &&
|
||||||
self.group_category &&
|
self.group_category &&
|
||||||
(self.group_category.unrestricted_self_signup? ||
|
(self.group_category.unrestricted_self_signup? ||
|
||||||
(self.group_category.restricted_self_signup? && self.has_common_section_with_user?(user)))
|
(self.group_category.restricted_self_signup? && self.has_common_section_with_user?(user)))
|
||||||
end
|
end
|
||||||
|
|
||||||
def free_association?(user)
|
def can_join?(user)
|
||||||
allow_join_request?(user) || allow_self_signup?(user)
|
auto_accept?(user) || allow_join_request?(user) || allow_self_signup?(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_leave?(user)
|
||||||
|
self.group_category.try(:allows_multiple_memberships?) || self.allow_self_signup?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
def participants(include_observers=false)
|
def participants(include_observers=false)
|
||||||
|
@ -125,6 +130,14 @@ class Group < ActiveRecord::Base
|
||||||
self.group_memberships.find_by_user_id(user && user.id)
|
self.group_memberships.find_by_user_id(user && user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_member?(user)
|
||||||
|
self.participating_group_memberships.find_by_user_id(user && user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_moderator?(user)
|
||||||
|
self.participating_group_memberships.moderators.find_by_user_id(user && user.id)
|
||||||
|
end
|
||||||
|
|
||||||
def short_name
|
def short_name
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
@ -175,11 +188,6 @@ class Group < ActiveRecord::Base
|
||||||
res += (self.context.course_code rescue self.context.name) if self.context
|
res += (self.context.course_code rescue self.context.name) if self.context
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def is_public
|
|
||||||
false
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_atom
|
def to_atom
|
||||||
Atom::Entry.new do |entry|
|
Atom::Entry.new do |entry|
|
||||||
entry.title = self.name
|
entry.title = self.name
|
||||||
|
@ -190,40 +198,26 @@ class Group < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_user(user)
|
def add_user(user, new_record_state=nil)
|
||||||
return nil if !user
|
return nil if !user
|
||||||
unless member = self.group_memberships.find_by_user_id(user.id)
|
attrs = { :user => user }
|
||||||
member = self.group_memberships.create(:user=>user)
|
new_record_state ||= case self.join_level
|
||||||
|
when 'invitation_only' then 'invited'
|
||||||
|
when 'parent_context_request' then 'requested'
|
||||||
|
when 'parent_context_auto_join' then 'accepted'
|
||||||
end
|
end
|
||||||
|
attrs[:workflow_state] = new_record_state if new_record_state
|
||||||
|
member = self.group_memberships.find_by_user_id(user.id)
|
||||||
|
member ||= self.group_memberships.create(attrs)
|
||||||
return member
|
return member
|
||||||
end
|
end
|
||||||
|
|
||||||
def invite_user(user)
|
def invite_user(user)
|
||||||
return nil if !user
|
self.add_user(user, 'invited')
|
||||||
res = nil
|
|
||||||
Group.transaction do
|
|
||||||
res = self.group_memberships.find_by_user_id(user.id)
|
|
||||||
unless res
|
|
||||||
res = self.group_memberships.build(:user => user)
|
|
||||||
res.workflow_state = 'invited'
|
|
||||||
res.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
res
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def request_user(user)
|
def request_user(user)
|
||||||
return nil if !user
|
self.add_user(user, 'requested')
|
||||||
res = nil
|
|
||||||
Group.transaction do
|
|
||||||
res = self.group_memberships.find_by_user_id(user.id)
|
|
||||||
unless res
|
|
||||||
res = self.group_memberships.build(:user => user)
|
|
||||||
res.workflow_state = 'requested'
|
|
||||||
res.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
res
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def invitees=(params)
|
def invitees=(params)
|
||||||
|
@ -239,10 +233,8 @@ class Group < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def peer_groups
|
def peer_groups
|
||||||
return [] if !self.context || self.student_organized?
|
return [] if !self.context || !self.group_category || self.group_category.allows_multiple_memberships?
|
||||||
category = self.group_category || GroupCategory.student_organized_for(self.context)
|
self.group_category.groups.find(:all, :conditions => ["id != ?", self.id])
|
||||||
return [] unless category
|
|
||||||
category.groups.find(:all, :conditions => ["id != ?", self.id])
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def migrate_content_links(html, from_course)
|
def migrate_content_links(html, from_course)
|
||||||
|
@ -274,6 +266,7 @@ class Group < ActiveRecord::Base
|
||||||
self.uuid ||= AutoHandle.generate_securish_uuid
|
self.uuid ||= AutoHandle.generate_securish_uuid
|
||||||
self.group_category ||= GroupCategory.student_organized_for(self.context)
|
self.group_category ||= GroupCategory.student_organized_for(self.context)
|
||||||
self.join_level ||= 'invitation_only'
|
self.join_level ||= 'invitation_only'
|
||||||
|
self.is_public ||= false
|
||||||
if self.context && self.context.is_a?(Course)
|
if self.context && self.context.is_a?(Course)
|
||||||
self.account = self.context.account
|
self.account = self.context.account
|
||||||
elsif self.context && self.context.is_a?(Account)
|
elsif self.context && self.context.is_a?(Account)
|
||||||
|
@ -296,34 +289,55 @@ class Group < ActiveRecord::Base
|
||||||
# if you modify this set_policy block, note that we've denormalized this
|
# if you modify this set_policy block, note that we've denormalized this
|
||||||
# permission check for efficiency -- see User#cached_contexts
|
# permission check for efficiency -- see User#cached_contexts
|
||||||
set_policy do
|
set_policy do
|
||||||
given { |user| user && self.participating_group_memberships.find_by_user_id(user.id) }
|
given { |user| user && self.has_member?(user) }
|
||||||
can :read and can :read_roster and can :manage and can :manage_content and can :manage_students and can :manage_admin_users and
|
can :create and
|
||||||
can :manage_files and
|
can :create_collaborations and
|
||||||
can :post_to_forum and
|
can :create_conferences and
|
||||||
can :send_messages and can :create_conferences and
|
can :delete and
|
||||||
can :create_collaborations and can :read_roster and
|
can :manage and
|
||||||
|
can :manage_admin_users and
|
||||||
can :manage_calendar and
|
can :manage_calendar and
|
||||||
can :update and can :delete and can :create and
|
can :manage_content and
|
||||||
can :manage_wiki
|
can :manage_files and
|
||||||
|
can :manage_students and
|
||||||
|
can :manage_wiki and
|
||||||
|
can :post_to_forum and
|
||||||
|
can :read and
|
||||||
|
can :read_roster and
|
||||||
|
can :send_messages and
|
||||||
|
can :update
|
||||||
|
|
||||||
# if I am a member of this group and I can moderate_forum in the group's context
|
# if I am a member of this group and I can moderate_forum in the group's context
|
||||||
# (makes it so group members cant edit each other's discussion entries)
|
# (makes it so group members cant edit each other's discussion entries)
|
||||||
given { |user, session| user && self.participating_group_memberships.find_by_user_id(user.id) && (!self.context || self.context.grants_right?(user, session, :moderate_forum)) }
|
given { |user, session| user && self.has_member?(user) && (!self.context || self.context.grants_right?(user, session, :moderate_forum)) }
|
||||||
can :moderate_forum
|
can :moderate_forum
|
||||||
|
|
||||||
given { |user| user && self.invited_users.include?(user) }
|
given { |user| user && self.has_moderator?(user) }
|
||||||
can :read
|
can :moderate_forum
|
||||||
|
|
||||||
given { |user, session| self.context && self.context.grants_right?(user, session, :participate_as_student) && self.context.allow_student_organized_groups }
|
given { |user, session| self.context && self.context.grants_right?(user, session, :participate_as_student) && self.context.allow_student_organized_groups }
|
||||||
can :create
|
can :create
|
||||||
|
|
||||||
given { |user, session| self.context && self.context.grants_right?(user, session, :manage_groups) }
|
given { |user, session| self.context && self.context.grants_right?(user, session, :manage_groups) }
|
||||||
can :read and can :read_roster and can :manage and can :manage_content and can :manage_students and can :manage_admin_users and can :update and can :delete and can :create and can :moderate_forum and can :post_to_forum and can :manage_wiki and can :manage_files and can :create_conferences
|
can :create and
|
||||||
|
can :create_conferences and
|
||||||
|
can :delete and
|
||||||
|
can :manage and
|
||||||
|
can :manage_admin_users and
|
||||||
|
can :manage_content and
|
||||||
|
can :manage_files and
|
||||||
|
can :manage_students and
|
||||||
|
can :manage_wiki and
|
||||||
|
can :moderate_forum and
|
||||||
|
can :post_to_forum and
|
||||||
|
can :read and
|
||||||
|
can :read_roster and
|
||||||
|
can :update
|
||||||
|
|
||||||
given { |user, session| self.context && self.context.grants_right?(user, session, :view_group_pages) }
|
given { |user, session| self.context && self.context.grants_right?(user, session, :view_group_pages) }
|
||||||
can :read and can :read_roster
|
can :read and can :read_roster
|
||||||
|
|
||||||
given { |user, session| self.context && self.free_association?(user) }
|
given { |user| user && self.can_join?(user) }
|
||||||
can :read_roster
|
can :read_roster
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -380,7 +394,7 @@ class Group < ActiveRecord::Base
|
||||||
def self.serialization_excludes; [:uuid]; end
|
def self.serialization_excludes; [:uuid]; end
|
||||||
|
|
||||||
def self.process_migration(data, migration)
|
def self.process_migration(data, migration)
|
||||||
groups = data['groups'] ? data['groups']: []
|
groups = data['groups'] || []
|
||||||
groups.each do |group|
|
groups.each do |group|
|
||||||
if migration.import_object?("groups", group['migration_id'])
|
if migration.import_object?("groups", group['migration_id'])
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -43,18 +43,23 @@ class GroupCategory < ActiveRecord::Base
|
||||||
role_category_for_context('imported', context)
|
role_category_for_context('imported', context)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def communities_for(context)
|
||||||
|
role_category_for_context('communities', context)
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
def name_for_role(role)
|
def name_for_role(role)
|
||||||
case role
|
case role
|
||||||
when 'student_organized' then t('group_categories.student_organized', "Student Groups")
|
when 'student_organized' then t('group_categories.student_organized', "Student Groups")
|
||||||
when 'imported' then t('group_categories.imported', "Imported Groups")
|
when 'imported' then t('group_categories.imported', "Imported Groups")
|
||||||
|
when 'communities' then t('group_categories.communities', "Communities")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def protected_roles_for_context(context)
|
def protected_roles_for_context(context)
|
||||||
case context
|
case context
|
||||||
when Course then ['student_organized', 'imported']
|
when Course then ['student_organized', 'imported']
|
||||||
when Account then ['imported']
|
when Account then ['communities', 'imported']
|
||||||
else []
|
else []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -74,6 +79,10 @@ class GroupCategory < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def communities?
|
||||||
|
self.role == 'communities'
|
||||||
|
end
|
||||||
|
|
||||||
def student_organized?
|
def student_organized?
|
||||||
self.role == 'student_organized'
|
self.role == 'student_organized'
|
||||||
end
|
end
|
||||||
|
@ -82,6 +91,16 @@ class GroupCategory < ActiveRecord::Base
|
||||||
self.role.present?
|
self.role.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def allows_multiple_memberships?
|
||||||
|
self.student_organized? || self.communities?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Communities can be joined by anyone,
|
||||||
|
# otherwise defer to the permission on the context
|
||||||
|
def available_for?(user)
|
||||||
|
self.communities? || (self.context && self.context.grants_right?(user, :participate_in_groups))
|
||||||
|
end
|
||||||
|
|
||||||
# this is preferred over setting self_signup directly. know that if you set
|
# this is preferred over setting self_signup directly. know that if you set
|
||||||
# self_signup directly to anything other than nil (or ''), 'restricted', or
|
# self_signup directly to anything other than nil (or ''), 'restricted', or
|
||||||
# 'enabled', it will behave as if you used 'enabled'.
|
# 'enabled', it will behave as if you used 'enabled'.
|
||||||
|
|
|
@ -23,7 +23,7 @@ class GroupMembership < ActiveRecord::Base
|
||||||
belongs_to :group
|
belongs_to :group
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
attr_accessible :group, :user
|
attr_accessible :group, :user, :workflow_state
|
||||||
|
|
||||||
before_save :ensure_mutually_exclusive_membership
|
before_save :ensure_mutually_exclusive_membership
|
||||||
before_save :assign_uuid
|
before_save :assign_uuid
|
||||||
|
@ -40,6 +40,7 @@ class GroupMembership < ActiveRecord::Base
|
||||||
named_scope :include_user, :include => :user
|
named_scope :include_user, :include => :user
|
||||||
|
|
||||||
named_scope :active, :conditions => ['group_memberships.workflow_state != ?', 'deleted']
|
named_scope :active, :conditions => ['group_memberships.workflow_state != ?', 'deleted']
|
||||||
|
named_scope :moderators, :conditions => { :moderator => true }
|
||||||
|
|
||||||
set_broadcast_policy do |p|
|
set_broadcast_policy do |p|
|
||||||
p.dispatch :new_context_group_membership
|
p.dispatch :new_context_group_membership
|
||||||
|
@ -111,6 +112,7 @@ class GroupMembership < ActiveRecord::Base
|
||||||
|
|
||||||
workflow do
|
workflow do
|
||||||
state :accepted
|
state :accepted
|
||||||
|
state :following
|
||||||
state :invited do
|
state :invited do
|
||||||
event :reject, :transitions_to => :rejected
|
event :reject, :transitions_to => :rejected
|
||||||
event :accept, :transitions_to => :accepted
|
event :accept, :transitions_to => :accepted
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
class AddModeratorFlagToGroupMemberships < ActiveRecord::Migration
|
||||||
|
tag :predeploy
|
||||||
|
|
||||||
|
def self.up
|
||||||
|
add_column :group_memberships, :moderator, :boolean
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.down
|
||||||
|
remove_column :group_memberships, :moderator
|
||||||
|
end
|
||||||
|
end
|
|
@ -60,6 +60,28 @@ describe GroupCategory do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "communities_for" do
|
||||||
|
it "should be nil in courses" do
|
||||||
|
course_model
|
||||||
|
GroupCategory.communities_for(@course).should be_nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be a category belonging to the account with role 'communities'" do
|
||||||
|
account = Account.default
|
||||||
|
category = GroupCategory.communities_for(account)
|
||||||
|
category.should_not be_nil
|
||||||
|
category.role.should eql('communities')
|
||||||
|
category.context.should eql(account)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be the the same category every time for the same account" do
|
||||||
|
account = Account.default
|
||||||
|
category1 = GroupCategory.communities_for(account)
|
||||||
|
category2 = GroupCategory.communities_for(account)
|
||||||
|
category1.id.should eql(category2.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "imported_for" do
|
context "imported_for" do
|
||||||
it "should be a category belonging to the account with role 'imported' in accounts" do
|
it "should be a category belonging to the account with role 'imported' in accounts" do
|
||||||
account = Account.default
|
account = Account.default
|
||||||
|
@ -94,6 +116,33 @@ describe GroupCategory do
|
||||||
GroupCategory.imported_for(course).should_not be_student_organized
|
GroupCategory.imported_for(course).should_not be_student_organized
|
||||||
GroupCategory.imported_for(course).should_not be_student_organized
|
GroupCategory.imported_for(course).should_not be_student_organized
|
||||||
course.group_categories.create(:name => 'Random Category').should_not be_student_organized
|
course.group_categories.create(:name => 'Random Category').should_not be_student_organized
|
||||||
|
GroupCategory.communities_for(account).should_not be_student_organized
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'communities?' do
|
||||||
|
it "should be true iff the role is 'communities', regardless of name" do
|
||||||
|
account = Account.default
|
||||||
|
course = course_model
|
||||||
|
GroupCategory.student_organized_for(course).should_not be_communities
|
||||||
|
account.group_categories.create(:name => 'Communities').should_not be_communities
|
||||||
|
GroupCategory.imported_for(course).should_not be_communities
|
||||||
|
GroupCategory.imported_for(course).should_not be_communities
|
||||||
|
course.group_categories.create(:name => 'Random Category').should_not be_communities
|
||||||
|
GroupCategory.communities_for(account).should be_communities
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'allows_multiple_memberships?' do
|
||||||
|
it "should be true iff the category is student organized or communities" do
|
||||||
|
account = Account.default
|
||||||
|
course = course_model
|
||||||
|
GroupCategory.student_organized_for(course).allows_multiple_memberships?.should be_true
|
||||||
|
account.group_categories.create(:name => 'Student Groups').allows_multiple_memberships?.should be_false
|
||||||
|
GroupCategory.imported_for(course).allows_multiple_memberships?.should be_false
|
||||||
|
GroupCategory.imported_for(course).allows_multiple_memberships?.should be_false
|
||||||
|
course.group_categories.create(:name => 'Random Category').allows_multiple_memberships?.should be_false
|
||||||
|
GroupCategory.communities_for(account).allows_multiple_memberships?.should be_true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,6 +155,7 @@ describe GroupCategory do
|
||||||
GroupCategory.imported_for(course).should be_protected
|
GroupCategory.imported_for(course).should be_protected
|
||||||
GroupCategory.imported_for(course).should be_protected
|
GroupCategory.imported_for(course).should be_protected
|
||||||
course.group_categories.create(:name => 'Random Category').should_not be_protected
|
course.group_categories.create(:name => 'Random Category').should_not be_protected
|
||||||
|
GroupCategory.communities_for(account).should be_protected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,11 @@ describe Group do
|
||||||
@group.wiki.should eql(WikiNamespace.default_for_context(@group).wiki)
|
@group.wiki.should eql(WikiNamespace.default_for_context(@group).wiki)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not be public" do
|
it "should be private by default" do
|
||||||
@group.is_public.should be_false
|
@group.is_public.should be_false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "#peer_groups" do
|
||||||
it "should find all peer groups" do
|
it "should find all peer groups" do
|
||||||
context = course_model
|
context = course_model
|
||||||
group_category = context.group_categories.create(:name => "worldCup")
|
group_category = context.group_categories.create(:name => "worldCup")
|
||||||
|
@ -60,6 +61,7 @@ describe Group do
|
||||||
group2 = Group.create!(:name=>"group2", :group_category=>group_category, :context => context)
|
group2 = Group.create!(:name=>"group2", :group_category=>group_category, :context => context)
|
||||||
group1.peer_groups.should be_empty
|
group1.peer_groups.should be_empty
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context "atom" do
|
context "atom" do
|
||||||
it "should have an atom name as it's own name" do
|
it "should have an atom name as it's own name" do
|
||||||
|
@ -73,7 +75,7 @@ describe Group do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "enrollment" do
|
context "add_user" do
|
||||||
it "should be able to add a person to the group" do
|
it "should be able to add a person to the group" do
|
||||||
user_model
|
user_model
|
||||||
pseudonym_model(:user_id => @user.id)
|
pseudonym_model(:user_id => @user.id)
|
||||||
|
@ -93,7 +95,7 @@ describe Group do
|
||||||
@group.users.count.should == 1
|
@group.users.count.should == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
it "adding a user should remove that user from peer groups" do
|
it "should remove that user from peer groups" do
|
||||||
context = course_model
|
context = course_model
|
||||||
group_category = context.group_categories.create!(:name => "worldCup")
|
group_category = context.group_categories.create!(:name => "worldCup")
|
||||||
group1 = Group.create!(:name=>"group1", :group_category=>group_category, :context => context)
|
group1 = Group.create!(:name=>"group1", :group_category=>group_category, :context => context)
|
||||||
|
@ -109,39 +111,28 @@ describe Group do
|
||||||
group1.users.should_not be_include(@user)
|
group1.users.should_not be_include(@user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# it "should be able to add more than one person at a time" do
|
it "should add a user at the right workflow_state by default" do
|
||||||
# user_model
|
pending "waiting to turn off auto join functionality"
|
||||||
# p1 = pseudonym_model(:user_id => @user.id)
|
{
|
||||||
# u1 = p1.user
|
'invitation_only' => 'invited',
|
||||||
# user_model
|
'parent_context_request' => 'requested',
|
||||||
# p2 = pseudonym_model(:user_id => @user.id)
|
'parent_context_auto_join' => 'accepted'
|
||||||
# u2 = p2.user
|
}.each do |join_level, workflow_state|
|
||||||
# @group.add_user([u1, u2])
|
usr = user_model
|
||||||
# @group.users.should be_include(u1)
|
grp = group_model(:join_level => join_level)
|
||||||
# @group.users.should be_include(u2)
|
grp.add_user(usr)
|
||||||
# end
|
grp.group_memberships.scoped(:conditions => { :workflow_state => workflow_state }).map(&:user_id).should be_include usr.id
|
||||||
|
end
|
||||||
it "should be able to add a person as a user instead as a pseudonym" do
|
|
||||||
user_model
|
|
||||||
@group.add_user(@user)
|
|
||||||
@group.users.should be_include(@user)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should be able to add a person with a user id" do
|
it "should allow specifying a workflow_state" do
|
||||||
user_model
|
pending "waiting to turn off auto join functionality"
|
||||||
@group.add_user(@user)
|
[ 'invited', 'requested', 'accepted' ].each do |workflow_state|
|
||||||
@group.users.should be_include(@user)
|
usr = user_model
|
||||||
|
@group.add_user(usr, workflow_state)
|
||||||
|
@group.group_memberships.scoped(:conditions => { :workflow_state => workflow_state }).map(&:user_id).should be_include usr.id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# it "should be able to add a person from their communication channel" do
|
|
||||||
# user_model
|
|
||||||
# communication_channel_model
|
|
||||||
# @group.users.should_not be_include(@user)
|
|
||||||
# @cc.user.should eql(@user)
|
|
||||||
# @group.add_user(@user)
|
|
||||||
# @group.users.should be_include(@user)
|
|
||||||
# end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should grant manage permissions for associated objects to group managers" do
|
it "should grant manage permissions for associated objects to group managers" do
|
||||||
|
@ -204,75 +195,130 @@ describe Group do
|
||||||
|
|
||||||
context "auto_accept?" do
|
context "auto_accept?" do
|
||||||
it "should be false unless join level is 'parent_context_auto_join'" do
|
it "should be false unless join level is 'parent_context_auto_join'" do
|
||||||
course_with_teacher
|
course_with_student
|
||||||
student = user_model
|
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = GroupCategory.student_organized_for(@course)
|
group_category = GroupCategory.student_organized_for(@course)
|
||||||
group = @course.groups.create(:group_category => group_category)
|
group1 = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
||||||
group.auto_accept?(student).should be_false
|
group2 = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_request')
|
||||||
|
group3 = @course.groups.create(:group_category => group_category, :join_level => 'invitation_only')
|
||||||
|
[group1, group2, group3].map{|g| g.auto_accept?(@student)}.should == [true, false, false]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should be false unless the group is student organized" do
|
it "should be false unless the group is student organized or a community" do
|
||||||
course_with_teacher
|
course_with_student
|
||||||
student = user_model
|
@account = @course.root_account
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = @course.group_categories.create(:name => "random category")
|
jl = 'parent_context_auto_join'
|
||||||
group = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
group1 = @course.groups.create(:group_category => @course.group_categories.create(:name => "random category"), :join_level => jl)
|
||||||
group.auto_accept?(student).should be_false
|
group2 = @course.groups.create(:group_category => GroupCategory.student_organized_for(@course), :join_level => jl)
|
||||||
end
|
group3 = @account.groups.create(:group_category => GroupCategory.communities_for(@account), :join_level => jl)
|
||||||
|
[group1, group2, group3].map{|g| g.auto_accept?(@student)}.should == [false, true, true]
|
||||||
it "should be true otherwise" do
|
|
||||||
course_with_teacher
|
|
||||||
student = user_model
|
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = GroupCategory.student_organized_for(@course)
|
|
||||||
group = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
|
||||||
group.auto_accept?(student).should be_true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "allow_join_request?" do
|
context "allow_join_request?" do
|
||||||
it "should be false unless join level is 'parent_context_auto_join' or 'parent_context_request'" do
|
it "should be false unless join level is 'parent_context_auto_join' or 'parent_context_request'" do
|
||||||
course_with_teacher
|
course_with_student
|
||||||
student = user_model
|
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = GroupCategory.student_organized_for(@course)
|
group_category = GroupCategory.student_organized_for(@course)
|
||||||
group = @course.groups.create(:group_category => group_category)
|
group1 = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
||||||
group.allow_join_request?(student).should be_false
|
group2 = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_request')
|
||||||
|
group3 = @course.groups.create(:group_category => group_category, :join_level => 'invitation_only')
|
||||||
|
[group1, group2, group3].map{|g| g.allow_join_request?(@student)}.should == [true, true, false]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should be false unless the group is student organized" do
|
it "should be false unless the group is student organized or a community" do
|
||||||
course_with_teacher
|
course_with_student
|
||||||
student = user_model
|
@account = @course.root_account
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = @course.group_categories.create(:name => "random category")
|
jl = 'parent_context_auto_join'
|
||||||
group = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
group1 = @course.groups.create(:group_category => @course.group_categories.create(:name => "random category"), :join_level => jl)
|
||||||
group.allow_join_request?(student).should be_false
|
group2 = @course.groups.create(:group_category => GroupCategory.student_organized_for(@course), :join_level => jl)
|
||||||
|
group3 = @account.groups.create(:group_category => GroupCategory.communities_for(@account), :join_level => jl)
|
||||||
|
[group1, group2, group3].map{|g| g.allow_join_request?(@student)}.should == [false, true, true]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should be true otherwise" do
|
context "allow_self_signup?" do
|
||||||
course_with_teacher
|
it "should follow the group category self signup option" do
|
||||||
student = user_model
|
course_with_student
|
||||||
@course.enroll_student(student)
|
|
||||||
@course.reload
|
|
||||||
|
|
||||||
group_category = GroupCategory.student_organized_for(@course)
|
group_category = GroupCategory.student_organized_for(@course)
|
||||||
|
group_category.configure_self_signup(true, false)
|
||||||
|
group_category.save!
|
||||||
|
group1 = @course.groups.create(:group_category => group_category)
|
||||||
|
group1.allow_self_signup?(@student).should be_true
|
||||||
|
|
||||||
group = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_auto_join')
|
group_category.configure_self_signup(true, true)
|
||||||
group.allow_join_request?(student).should be_true
|
group_category.save!
|
||||||
|
group2 = @course.groups.create(:group_category => group_category)
|
||||||
|
group2.allow_self_signup?(@student).should be_true
|
||||||
|
|
||||||
group = @course.groups.create(:group_category => group_category, :join_level => 'parent_context_request')
|
group_category.configure_self_signup(false, false)
|
||||||
group.allow_join_request?(student).should be_true
|
group_category.save!
|
||||||
|
group3 = @course.groups.create(:group_category => group_category)
|
||||||
|
group3.allow_self_signup?(@student).should be_false
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should correctly handle restricted course sections" do
|
||||||
|
course_with_student
|
||||||
|
@other_section = @course.course_sections.create!(:name => "Other Section")
|
||||||
|
@other_student = @course.enroll_student(user_model, {:section => @other_section}).user
|
||||||
|
|
||||||
|
group_category = GroupCategory.student_organized_for(@course)
|
||||||
|
group_category.configure_self_signup(true, true)
|
||||||
|
group_category.save!
|
||||||
|
group1 = @course.groups.create(:group_category => group_category)
|
||||||
|
group1.allow_self_signup?(@student).should be_true
|
||||||
|
group1.add_user(@student)
|
||||||
|
group1.reload
|
||||||
|
group1.allow_self_signup?(@other_student).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "has_member?" do
|
||||||
|
it "should be true for accepted memberships, regardless of moderator flag" do
|
||||||
|
@user1 = user_model
|
||||||
|
@user2 = user_model
|
||||||
|
@user3 = user_model
|
||||||
|
@user4 = user_model
|
||||||
|
@user5 = user_model
|
||||||
|
|
||||||
|
@group.add_user(@user1, 'accepted')
|
||||||
|
@group.add_user(@user2, 'accepted')
|
||||||
|
@group.add_user(@user3, 'invited')
|
||||||
|
@group.add_user(@user4, 'requested')
|
||||||
|
@group.add_user(@user5, 'rejected')
|
||||||
|
GroupMembership.update_all({:moderator => true}, {:group_id => @group.id, :user_id => @user2.id})
|
||||||
|
|
||||||
|
@group.has_member?(@user1).should be_true
|
||||||
|
@group.has_member?(@user2).should be_true
|
||||||
|
@group.has_member?(@user3).should be_true # false when we turn auto_join off
|
||||||
|
@group.has_member?(@user4).should be_true # false when we turn auto_join off
|
||||||
|
@group.has_member?(@user5).should be_false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "has_moderator?" do
|
||||||
|
it "should be true for accepted memberships, with moderator flag" do
|
||||||
|
@user1 = user_model
|
||||||
|
@user2 = user_model
|
||||||
|
@user3 = user_model
|
||||||
|
@user4 = user_model
|
||||||
|
@user5 = user_model
|
||||||
|
|
||||||
|
@group.add_user(@user1, 'accepted')
|
||||||
|
@group.add_user(@user2, 'accepted')
|
||||||
|
@group.add_user(@user3, 'invited')
|
||||||
|
@group.add_user(@user4, 'requested')
|
||||||
|
@group.add_user(@user5, 'rejected')
|
||||||
|
GroupMembership.update_all({:moderator => true}, {:group_id => @group.id, :user_id => [@user2.id, @user3.id, @user4.id, @user5.id]})
|
||||||
|
|
||||||
|
@group.has_moderator?(@user1).should be_false
|
||||||
|
@group.has_moderator?(@user2).should be_true
|
||||||
|
@group.has_moderator?(@user3).should be_true # false when we turn auto_join off
|
||||||
|
@group.has_moderator?(@user4).should be_true # false when we turn auto_join off
|
||||||
|
@group.has_moderator?(@user5).should be_false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue