canvas-lms/app/models/collaboration.rb

217 lines
5.7 KiB
Ruby

#
# Copyright (C) 2011 Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class Collaboration < ActiveRecord::Base
attr_accessible :user, :title, :description
attr_readonly :collaboration_type
include Workflow
include SendToStream
belongs_to :user
has_many :collaborators, :dependent => :destroy
has_many :users, :through => :collaborators
belongs_to :context, :polymorphic => true
before_save :generate_document
before_save :assign_uuid
before_save :set_context_code
after_save :include_author_as_collaborator
after_save :touch_context
validates_length_of :description, :maximum => maximum_text_length, :allow_nil => true, :allow_blank => true
serialize :data
before_destroy :destroy_collaborators
adheres_to_policy
workflow do
state :active
state :deleted
end
on_create_send_to_streams do
[self.user_id] + self.collaborators.map(&:user_id)
end
def include_author_as_collaborator
Collaborator.find_or_create_by_user_id_and_collaboration_id(self.user_id, self.id)
end
alias_method :destroy!, :destroy
def destroy
self.workflow_state = 'deleted'
self.deleted_at = Time.now
save!
end
def restore
self.workflow_state = 'active'
self.save
end
def style_class
nil
end
def self.collaboration_class(type)
found_config = Collaboration.collaboration_types.find{|c| c['type'].titleize.gsub(/\s/, "") == type }
klass = found_config && "#{type}Collaboration".constantize rescue nil
klass = nil unless klass && klass.ancestors.include?(Collaboration) && klass.config
klass
end
def self.typed_collaboration_instance(type)
found_config = Collaboration.collaboration_types.find{|c| c['name'] == type }
klass = found_config && collaboration_class(found_config['type'].titleize.gsub(/\s/, "")) rescue nil
if klass && klass.ancestors.include?(Collaboration) && klass.config
res = klass.new
res.collaboration_type = found_config['name']
res
else
raise "Unrecognized collaboration type: #{type}"
end
end
named_scope :for_context_codes, lambda { |context_codes| {
:conditions => {:context_code => context_codes} }
}
named_scope :active, lambda{
{:conditions => ['collaborations.workflow_state != ?', 'deleted']}
}
set_policy do
given {|user, session| !self.new_record? && (self.user_id == user.id || self.users.include?(user)) }
set { can :read }
given {|user, session| self.cached_context_grants_right?(user, session, :create_collaborations) }
set { can :create }
given {|user, session| self.cached_context_grants_right?(user, session, :manage_content) }
set { can :read and can :update and can :delete }
given {|user, session| user && self.user_id == user.id && self.cached_context_grants_right?(user, session, :create_collaborations) }
set { can :read and can :update and can :delete }
end
def assign_uuid
self.uuid ||= UUIDSingleton.instance.generate
end
protected :assign_uuid
def set_context_code
self.context_code = "#{self.context_type.underscore}_#{self.context_id}" rescue nil
end
protected :set_context_code
def destroy_collaborators
self.collaborators.each do |c|
c.destroy
end
end
protected :destroy_collaborators
def collaborator_ids
self.collaborators.map(&:user_id).join(',')
end
def title
read_attribute(:title) || (self.parse_data.title rescue nil) || "Unnamed Collaboration"
end
def service_name
"Collaboration"
end
def delete_document
end
def initialize_document
end
def generate_document
self.assign_uuid
initialize_document
end
def user_can_access_document_type?(user)
true
end
def valid_user?(user)
return false unless self.grants_right?(user, nil, :read)
user_can_access_document_type?(user)
end
def authorize_user(user)
end
def remove_users_from_document(users_to_remove)
end
def add_users_to_document(users_to_add)
end
def collaboration_users=(users)
self.save
generate_document
users_to_remove = self.users - users
remove_users_from_document(users_to_remove)
self.collaborators.select{|c| !users.include?(c.user)}.each{|c|
c.destroy
}
new_users = users - self.users
add_users_to_document(new_users)
new_users.each do |u|
self.collaborators.create(:user => u, :authorized_service_user_id => u.gmail)
end
self.save
self.users
end
def parse_data
nil
end
DEFAULT_COLLABORATION_TYPES = [
{'name' => 'Google Docs', 'type' => 'google_docs'},
{'name' => 'EtherPad', 'type' => 'etherpad'}
]
def self.collaboration_types
@collab_types ||= (YAML.load_file(RAILS_ROOT + "/config/collaborations.yml")[RAILS_ENV] rescue nil) || DEFAULT_COLLABORATION_TYPES
end
def self.any_collaborations_configured?
collaboration_types.any? do |type|
collaboration_class(type['type'].titleize.gsub(/\s/, "")) rescue false
end
end
def config
raise "not implemented"
end
named_scope :after, lambda{|date|
{:conditions => ['collaborations.updated_at > ?', date]}
}
def self.serialization_excludes; [:uuid]; end
end