app/models/abilities/member_ability.rb
# This file is part of Mconf-Web, a web application that provides access
# to the Mconf webconferencing system. Copyright (C) 2010-2015 Mconf.
#
# This file is licensed under the Affero General Public License version
# 3 or later. See the LICENSE file.
module Abilities
class MemberAbility < BaseAbility
def register_abilities(user)
abilities_for_bigbluebutton_rails(user)
# Users
can [:index, :show, :fellows, :current, :select], User
can [:edit, :update, :disable, :update_logo], User, id: user.id
can :update_password, User do |target_user|
user == target_user &&
(Site.current.local_auth_enabled? && target_user.local_auth?)
end
can :update_full_name, User do |target_user|
user == target_user &&
!(target_user.created_by_shib? && Site.current.shib_update_users?)
end
# Spaces
can :select, Space
can [:create, :new], Space unless Site.current.forbid_user_space_creation?
can [:index], Space
can [:show, :webconference, :meetings, :index_event], Space, public: true
can [:show, :webconference, :meetings, :index_event], Space do |space|
space.users.include?(user)
end
can [:leave], Space do |space|
space.users.include?(user) && !space.is_last_admin?(user)
end
# Only the admin can disable or update information on a space
# Only global admins can destroy spaces
can [:edit, :update, :update_logo, :user_permissions,
:webconference_options, :disable, :edit_recording], Space do |space|
space.admins.include?(user)
end
# Join Requests
# TODO: make everything for events also
# normal users can request membership
# admins in a space can invite users
can [:create, :new], JoinRequest
# users that created a join request can do a few things over it
can [:decline], JoinRequest do |jr|
jr.group.try(:is_a?, Space) && jr.try(:candidate) == user
end
# users can accept invitations they received, space admins can accept requests
# made to that space.
can :accept, JoinRequest do |jr|
group = jr.group
if group.try(:is_a?, Space)
(jr.is_invite? && jr.try(:candidate) == user) ||
(jr.is_request? && group.admins.include?(user))
else
false
end
end
alias_action :admissions_join_requests, :invite, to: :manage_join_requests
# space admins can list requests and invite new members
can [:manage_join_requests], Space do |s|
s.admins.include?(user)
end
# space admins can work with all join requests in the space
can [:create, :new, :decline], JoinRequest do |jr|
group = jr.group
group.try(:is_a?, Space) && group.admins.include?(user)
end
# Posts
# TODO: maybe space admins should be able to alter posts
can :index, Post # restricted through Space
can :show, Post, space: { public: true }
can [:show, :create, :new, :reply_post], Post do |post|
post.space.users.include?(user)
end
can [:show, :reply_post, :edit, :update, :destroy], Post, author_id: user.id
# Attachments
can :index, Attachment # restricted through Space
can :manage, Attachment do |attach|
attach.space.admins.include?(user)
end
can [:show, :create, :new], Attachment do |attach|
attach.space.users.include?(user)
end
can [:destroy], Attachment do |attach|
attach.space.users.include?(user) &&
attach.author_id == user.id
end
can [:show], Attachment, space: { public: true }
# Permissions
# Only space admins can update user roles/permissions
can :index, Permission # restricted through Space
can [:show, :edit], Permission do |perm|
case perm.subject_type
when "Space"
perm.subject.admins.include?(user)
else
false
end
end
can [:update, :destroy], Permission do |perm|
case perm.subject_type
when "Space"
perm.subject.admins.include?(user) &&
!perm.subject.is_last_admin?(perm.user)
else
false
end
end
permissions_for_events(user)
restrict_access_to_disabled_resources(user)
restrict_access_to_unapproved_resources(user)
end
private
def permissions_for_events(user)
can [:select, :show, :index, :create, :new], Event
# users can't create events in a space they don't belong to
cannot [:create, :new], Event do |event|
if event.owner_type == 'Space'
owner = Space.with_disabled.find(event.owner_id)
!owner.users.include?(user)
end
end
can [:edit, :update, :destroy, :invite, :send_invitation], Event do |e|
event_can_be_managed_by(e, user)
end
can :register, Event do |e|
# not the owner and the event is public or in a space the user has access to
Participant.where(owner_id: user.id, event_id: e.id).empty? &&
(e.public || (e.owner_type == 'Space' && e.owner.users.include?(user)))
end
can :destroy, Participant do |p|
p.owner == user
end
can [:show, :edit, :update, :destroy], Participant do |p|
event_can_be_managed_by(p.event, user)
end
can [:index, :create, :new], Participant
end
def event_can_be_managed_by(event, user)
case event.owner_type
when 'User' then
event.owner_id == user.id
when 'Space' then
organizer = user.permissions.where(
subject_type: 'Event', role_id: Role.find_by_name('Organizer'), subject_id: event.id
).any?
space_admin = user.permissions.where(
subject_type: 'Space', role_id: Role.find_by_name('Admin'), subject_id: event.owner_id
).any?
organizer || space_admin
end
end
# Abilities for the resources from BigbluebuttonRails.
# Not everything is done here, some authorization steps are done by the gem
# BigbluebuttonRails itself.
# These actions have a difference from most of the other resources: most of them are only
# accessible by admins, including standard actions such as `:show`, `:edit`, and `:index`.
# However, normal users also have access to limited version of these actions, such as a page
# to edit just a few attributes of a room or a recording. The methods for these actions are
# in controllers other than the standard controllers for these resources (e.g.
# BigbluebuttonRoomsController) and are named differently to differ than from the standard
# actions (e.g. `:space_show` is a limited version of `:show` for rooms in spaces).
def abilities_for_bigbluebutton_rails(user)
# Can do the actions below if he's the owner or if he belongs to the space (with any role)
# that owns the room.
# `:create_meeting` is a custom name, not an action that exists in the controller
can [:create_meeting, :fetch_recordings,
:invitation, :send_invitation], BigbluebuttonRoom do |room|
user_is_owner_or_belongs_to_rooms_space(user, room)
end
# For user rooms only the owner can end meetings.
# In spaces only the admins and the person that started the meeting can end it.
can :end, BigbluebuttonRoom do |room|
user_can_end_meeting(user, room)
end
# Users can recording meetings in their rooms, but only if they have the record flag set.
# `:record_meeting` is a custom name, not an action that exists in the controller
can :record_meeting, BigbluebuttonRoom do |room|
user.can_record && user_is_owner_or_belongs_to_rooms_space(user, room)
end
# Owners of personal rooms or admins of a space can edit rooms
can [:user_edit, :update], BigbluebuttonRoom do |room|
user_is_owner_or_admin_of_rooms_space(user, room)
end
# some actions in rooms should be accessible to any logged user
# some of them will do the authorization themselves (e.g. permissions for :join
# will change depending on the user and the target room)
can [:invite, :invite_userid, :running, :join, :join_mobile], BigbluebuttonRoom
# a user can play recordings of his own room or recordings of
# rooms of either public spaces or spaces he's a member of
can [:play], BigbluebuttonRecording do |recording|
user_is_member_of_meetings_space(user, recording) ||
meetings_space_is_public(recording) ||
user_is_owner_of_recording(user, recording)
end
# a user can edit and unpublish (see #447) his recordings and recordings in spaces where he's an admin
can [:update, :unpublish], BigbluebuttonRecording do |recording|
user_is_owner_of_recording(user, recording) ||
user_is_admin_of_meetings_space(user, recording)
end
# a user can see and edit his recordings
can [:user_show, :user_edit], BigbluebuttonRecording do |recording|
user_is_owner_of_recording(user, recording)
end
# admins can edit recordings in their spaces
can [:space_edit], BigbluebuttonRecording do |recording|
user_is_admin_of_meetings_space(user, recording)
end
# recordings can be viewed in spaces if the space is public or the user belongs to the space
can [:space_show], BigbluebuttonRecording do |recording|
user_is_member_of_meetings_space(user, recording) ||
meetings_space_is_public(recording)
end
end
# Whether `user` is the owner of `room` or belongs to the space that owns `room`.
def user_is_owner_or_belongs_to_rooms_space(user, room)
if (room.owner_type == "User" && room.owner.id == user.id)
true
elsif (room.owner_type == "Space")
space = Space.find_by(id: room.owner.id)
if space.present?
space.users.include?(user)
else
false
end
else
false
end
end
# Whether `user` is the owner of `room` or admin of the space that owns `room`.
def user_is_owner_or_admin_of_rooms_space(user, room)
if (room.owner_type == "User" && room.owner.id == user.id)
true
elsif (room.owner_type == "Space")
space = Space.find_by(id: room.owner.id)
if space.present?
space.admins.include?(user)
else
false
end
else
false
end
end
# Whether `user` can end the meeting in `room`.
def user_can_end_meeting(user, room)
if (room.owner_type == "User" && room.owner.id == user.id)
true
elsif (room.owner_type == "Space")
space = Space.find(room.owner.id)
if space.admins.include?(user)
true
elsif room.user_created_meeting?(user)
true
else
false
end
else
false
end
end
# Whether `user` owns the room that owns `recording`.
def user_is_owner_of_recording(user, recording)
response = false
unless recording.room.nil?
if recording.room.owner_type == "User" && recording.room.owner_id == user.id
response = true
end
end
response
end
# Whether the user is an admin of the space that owns the room that owns `recording`.
def user_is_admin_of_meetings_space(user, recording)
response = false
unless recording.room.nil?
if recording.room.owner_type == "Space"
space = Space.find(recording.room.owner_id)
response = space.admins.include?(user)
end
end
response
end
# Whether the user is a member of the space that owns the room that owns `recording`.
def user_is_member_of_meetings_space(user, recording)
response = false
unless recording.room.nil?
if recording.room.owner_type == "Space"
space = Space.find(recording.room.owner_id)
response = space.users.include?(user)
end
end
response
end
# Whether the space that owns the room that owns `recording` is public.
def meetings_space_is_public(recording)
recording.room.try(:public?)
end
end
end